问题:大多数现代 API 提供 OpenAPI 规范,而非 Delphi SDK
如果您曾经在 Delphi 中集成过现代 REST API,工作流可能是这样的:阅读文档、围绕 TIdHTTP 或 TNetHTTPClient 手写包装器、将请求体粘贴到字符串字面值中、用 TJSONObject 解析响应、与 TDateTime 序列化作斗争、对每个端点重复这一过程。它可以工作,但无法扩展。API 有 80 个端点,您包装了 8 个,供应商下个月添加了 10 个,您的包装器就会腐烂。
OpenAPI(以前称为 Swagger)的承诺是供应商发布一个机器可读的描述——一个 YAML 或 JSON 文件——而生成器将其转换为您选择的语言中的类型化客户端。对于大多数语言,这非常有效:openapi-generator 和 swagger-codegen 为 Python、TypeScript、Go、Java、C#、Rust 和许多其他语言生成符合习惯的客户端。
对于 Delphi,这一过程历来不那么顺畅。本文比较了 2026 年的两个主要选项——长期存在的开源 swagger-codegen Delphi 生成器和 eSeGeCe 的原生商业 sgcOpenAPI——并展示了它们从相同输入规范生成的内容。
关于 swagger-codegen 和 openapi-generator
Swagger 项目现在在 SmartBear 旗下,提供 swagger-codegen。在 2018 年社区分叉后,一个并行项目 openapi-generator 成为许多语言事实上的标准。两个工具都通过 Mustache 模板支持一长串目标语言。Delphi 生成器(swagger-codegen 中的 delphi,加上社区模板)存在,但它一直是二线目标,由偶尔的志愿者维护。
截至撰写本文时,openapi-generator 中的 Delphi 模板生成的代码可在较旧的 Delphi 版本上编译,但在现代 Delphi (D11/D12/D13) 上存在已知问题:可空字段处理不正确、缺少较新 RTL 的 {$IFDEF} 守卫、不支持 OpenAPI 3.1、不支持流式响应,以及依赖于特定 HTTP 客户端库版本的运行时。针对 Delphi 生成器的几个长期存在的 GitHub 问题已经打开多年。您的体验会因规范而异。
关于 sgcOpenAPI
sgcOpenAPI 是 eSeGeCe 的原生 Delphi 工具。它解析 OpenAPI 3.0(现在是 3.1)规范并发出遵循 sgc 命名约定的 Delphi 单元:客户端的 Tsgc[Api]Client、每个模式对象的 Tsgc[Api]_[Model],以及每个操作一个方法。生成的代码使用 sgcWebSockets 的 TsgcHTTPComponentClient 作为传输,因此身份验证、重试、TLS 和 HTTP/2 都免费继承。
由于生成器本身是用 Delphi 编写的,它可以嵌入到 Delphi 工具中、从命令行运行,或从构建脚本调用。输出是普通的 .pas 文件,除 sgcWebSockets 之外没有运行时依赖——没有 JVM、没有 Node、没有 Python、没有模板引擎。
功能比较
| 功能 | swagger-codegen / openapi-generator (Delphi 目标) | sgcOpenAPI |
|---|---|---|
| OpenAPI 2.0 (Swagger) | 是 | 是 |
| OpenAPI 3.0 | 是 (openapi-generator) | 是 |
| OpenAPI 3.1 | 撰写时有限 | 是 |
| 运行时要求 | 需要 Java 11+ 来运行生成器 | 无(原生 Delphi exe) |
| 目标 Delphi 版本 | D10.x 上尽力而为,撰写时在 D11+ 上经常损坏 | D7 至 D13 |
| HTTP 后端 | 当前 Delphi 模板中默认为 Indy | sgcHTTPComponentClient(Indy / ICS / SChannel,加上 HTTP/2) |
| 异步/流式响应 | 有限 | 是 |
| OAuth2 / API 密钥 / bearer 身份验证 | 部分 | 是,原生组件 |
多态性(oneOf、allOf、discriminator) | 有限 | 是 |
| 可空字段 | 不一致 | 是 (TsgcNullable<T>) |
| 文件上传/多部分 | 部分 | 是 |
| 服务器存根生成 | 是(主要是其他语言) | 是(带 sgcWebSocketHTTPServer 的 Delphi 服务器存根) |
| 许可 | 开源 (Apache 2.0) | 商业 |
工作流比较
swagger-codegen 工作流
- 安装 Java 11 或更高版本。
- 下载
openapi-generator-cliJAR。 - 运行
java -jar openapi-generator-cli.jar generate -i spec.yaml -g delphi -o ./out。 - 在 IDE 中打开生成的
.pas文件。添加 Indy 运行时路径。修复 Delphi 版本的任何编译问题。修补可空处理。每次规范更改后重新运行。 - 生成的客户端依赖于模板提供的单独的运行时支持单元。您将该单元与项目一起发布。
sgcOpenAPI 工作流
- 打开 sgcOpenAPI IDE 或调用 CLI:
sgcOpenAPI.exe -i spec.yaml -o ./out。 - 在 IDE 中打开生成的单元。它使用
TsgcHTTPComponentClient,如果您使用 sgcWebSockets,您已经拥有它。 - 将生成的客户端组件放在窗体上,设置基础 URL 和凭据,并调用类型化方法。
并排:生成的 GET /users/{id} 方法
相同的 OpenAPI 片段、两种工具、相同的操作。辅助方法名称和确切格式略经美化以提高清晰度,但方法上的差异是真实的。
swagger-codegen(Delphi 目标,简化)
function TUsersApi.GetUserById(const Id: Int64): TUser;
var
HttpRequest: TIdHTTP;
Path, Response: string;
JsonValue: TJSONValue;
begin
Path := StringReplace(BasePath + '/users/{id}', '{id}', IntToStr(Id), [rfReplaceAll]);
HttpRequest := TIdHTTP.Create(nil);
try
HttpRequest.Request.CustomHeaders.AddValue('Authorization', 'Bearer ' + FApiKey);
Response := HttpRequest.Get(Path);
finally
HttpRequest.Free;
end;
JsonValue := TJSONObject.ParseJSONValue(Response);
try
Result := TUser.Create;
Result.Id := (JsonValue as TJSONObject).GetValue<Int64>('id');
Result.Name := (JsonValue as TJSONObject).GetValue<string>('name');
// ... nullable fields handled inconsistently ...
finally
JsonValue.Free;
end;
end;
sgcOpenAPI
function TsgcUsersApiClient.GetUserById(const aId: Int64): TsgcUser;
var
vResponse: TsgcAPIResponse;
begin
Result := nil;
vResponse := DoGet(Format('/users/%d', [aId]));
Try
if vResponse.StatusCode = 200 then
Result := TsgcUser.FromJSON(vResponse.Content);
Finally
vResponse.Free;
End;
end;
// TsgcUser is generated with typed nullable fields:
// property Id: Int64 read FId write FId;
// property Name: string read FName write FName;
// property Email: TsgcNullable<string> read FEmail write FEmail;
// property CreatedAt: TDateTime read FCreatedAt write FCreatedAt;
//
// Authentication, retry, HTTP/2, TLS are configured on the
// underlying TsgcHTTPComponentClient once, not per-method.
值得注意的差异:
- sgcOpenAPI 将传输(组件级设置)与操作(类型化方法)分离,因此 auth、重试和 TLS 只需配置一次。
- 可空字段使用类型化包装器
TsgcNullable<T>,可区分"缺席"、"null"和"值"——与 OpenAPI 3.x 语义匹配。 - 日期/时间字段使用真正的
TDateTime和正确的 ISO 8601 解析器,而不是您稍后解析的字符串。 - 生成的客户端使用 sgcWebSockets HTTP 组件,如果服务器通过 ALPN 广告,则透明支持 HTTP/2。
服务器存根
两个工具都可以生成服务器端代码,但截至撰写本文时,openapi-generator 中的 Delphi 服务器模板很简单。sgcOpenAPI 生成基于 TsgcWebSocketHTTPServer 的处理程序,每个操作一个虚拟方法、请求验证、响应塑形和内置的 OpenAPI 浏览器端点。对于希望单个 Delphi 项目公开 API 并由 Delphi 客户端消费它的内部服务,往返非常短。
swagger-codegen 仍然是正确选择的时候
- 您已经在许多语言中标准化使用
openapi-generator,并希望在 CI 管道中使用一个工具。 - 您的规范很小且稳定,您不需要 OpenAPI 3.1 功能。
- 您可以轻松修补生成的 Delphi 以适应您的目标版本。
- 由于许可原因,您不能使用商业软件。
sgcOpenAPI 节省真正时间的时候
- 您在当前 Delphi 版本(D11 / D12 / D13)上,撰写时 swagger-codegen Delphi 模板在那里很脆。
- 您的规范使用 OpenAPI 3.1、
oneOf/discriminator、可空字段、文件上传或异步流式传输。 - 您已经使用 sgcWebSockets,并希望一致的组件模型和单个 HTTP 栈。
- 您需要 HTTP/2、TLS、OAuth2 和重试"开箱即用",无需重写生成的客户端。
结束思考
从 OpenAPI 生成代码是那种在项目生命周期中累积的生产力胜利之一——前提是生成器跟上规范和您的 Delphi 版本。swagger-codegen / openapi-generator 是出色的多语言工具,但它们的 Delphi 目标在历史上被视为尽力而为。sgcOpenAPI 是一个专注的、原生的 Delphi 替代品,无需 Java 依赖且无需手动修补周期,即可交付可编译的、符合习惯的、完整功能的 OpenAPI 3.0 / 3.1 客户端(和服务器存根)。对于已经集成 REST API 的大多数 Delphi 团队,它在供应商首次更新其规范时就为自己付清成本。