sgcOpenAPI 的下一个版本 — 2026.6,将于六月发布 — 推出了一个全新的组件:TsgcHTTPServer_OpenAPI。这是一个单一的、自包含的 Delphi 组件,内嵌 HTTP 服务器并托管 OpenAPI 3.0 服务。将其放到窗体上,指向一份规范(或通过 RTTI 属性从 Delphi 类生成规范),设置 Active := True,即可拥有一个带有自动提供的 Swagger UI 的、有文档化的 REST API。
本次更新的重头戏是 sgcOpenAPI 托管 HTTP 服务器时不再需要 sgcWebSockets。新组件完全由 sgcOpenAPI 提供、打包和安装。如果您已经使用 sgcWebSockets,之前的 TsgcWSServer_API_OpenAPI 组件将保持原样运作 — 二者内部共享同一套引擎。
一个组件囊括的内容
TsgcHTTPServer_OpenAPI 整合了三大要素:
- 一个内嵌 HTTP 服务器(基于 Indy),具有常规的
Bindings、Port和Active属性。 - OpenAPI 引擎:规范解析、带
{paramName}段的路径模板路由、JSON-Schema 验证、CORS、异常处理。 - 两个自动提供的端点:位于
/openapi.json的规范和位于/docs的 Swagger UI。两者默认均已启用,可在OpenAPIOptions.Endpoint中切换。
快速入门 — 最小示例
托管一个带 Swagger UI 的可用 OpenAPI 服务器,所需要的就是这些:
uses
sgcHTTPServer_OpenAPI;
var
oServer: TsgcHTTPServer_OpenAPI;
begin
oServer := TsgcHTTPServer_OpenAPI.Create(nil);
try
oServer.Bindings.Add.Port := 8080;
oServer.LoadFromFile('petstore.json');
oServer.OnRequest := MyOnRequest;
oServer.Active := True;
Readln;
finally
oServer.Free;
end;
end;
访问 http://localhost:8080/docs 查看 Swagger UI,访问 http://localhost:8080/openapi.json 获取规范。规范中定义的每一个操作都会被路由到您的 MyOnRequest 处理器,并附带已解析的 operationId 和完整构建好的请求上下文。
Spec-First — 加载已有的 OpenAPI 3.0 文件
如果您已经有一份 OpenAPI 3.0 的 JSON 或 YAML 文件(例如 Petstore、一份内部 API 合约或一份您想要模拟的公共架构),spec-first 是提供该服务最快的方式。LoadFromFile 读取并解析规范,根据 paths 部分构建路由表,然后将每一个传入请求与之匹配。
每条路由的 operationId 是分派的关键。在 OnRequest 中,您依次处理每一个操作:
uses
sgcHTTP_OpenAPI_Server, sgcHTTP_OpenAPI_Server_Engine,
sgcHTTPServer_OpenAPI;
procedure TForm1.OnOpenAPIRequest(Sender: TObject;
const aOperationId: string; const aContext: TsgcOpenAPIServerContext;
var Handled: Boolean);
begin
Handled := True;
if aOperationId = 'listPets' then
HandleListPets(aContext)
else if aOperationId = 'getPetById' then
HandleGetPetById(aContext)
else if aOperationId = 'createPet' then
HandleCreatePet(aContext)
else
Handled := False;
end;
procedure TForm1.HandleGetPetById(const aContext: TsgcOpenAPIServerContext);
var
vId, vPetJSON: string;
begin
vId := aContext.PathParamAsString('petId');
vPetJSON := FPets.Values[vId];
if vPetJSON <> '' then
aContext.RespondJSON(200, vPetJSON)
else
aContext.RespondError(404, 'Not Found', 'Pet ' + vId + ' not found');
end;
TsgcOpenAPIServerContext 为请求中的所有内容提供了类型化访问器:用于模板段的 PathParamAsString / PathParamAsInteger,带默认值的 QueryParamAsString / QueryParamAsInteger / QueryParamAsBoolean,用于请求体的 BodyAsString / BodyAsJSON,以及用于任意传入头的 HeaderValue。要进行响应,可以使用辅助方法 RespondJSON(code, content) 和 RespondError(code, title, detail),或者直接设置 Response.Code、Response.ContentType 和 Response.Content 以获得完全控制。
Code-First — 从 Delphi 类生成规范
如果您更愿意用 Delphi 编写 API 合约并让规范自动生成,请用 RTTI 属性装饰一个类。TsgcOpenAPICodeFirstScanner 会遍历该类,构建一份完整的 OpenAPI 3.0 JSON 文档,然后您可以通过 LoadFromString 将其加载到服务器中。这需要 Delphi XE7 或更新版本(以支持扩展 RTTI)。
uses
sgcHTTP_OpenAPI_Server_CodeFirst;
type
[sgcServiceContract('Task Manager API',
'A simple task management demo', '1.0.0')]
[sgcRoute('/api/v1')]
TTaskManagerService = class
public
[sgcHttpGet]
[sgcRoute('/tasks')]
[sgcSummary('List all tasks')]
[sgcTag('Tasks')]
[sgcResponse(200, 'A list of tasks')]
procedure ListTasks([sgcFromQuery] const status: string); virtual;
[sgcHttpPost]
[sgcRoute('/tasks')]
[sgcSummary('Create a new task')]
[sgcTag('Tasks')]
[sgcResponse(201, 'Task created successfully')]
procedure CreateTask([sgcFromBody] const body: string); virtual;
[sgcHttpGet]
[sgcRoute('/tasks/{taskId}')]
[sgcSummary('Get a task by ID')]
[sgcTag('Tasks')]
[sgcResponse(200, 'The requested task')]
[sgcResponse(404, 'Task not found')]
procedure GetTask([sgcFromPath][sgcRequired]
const taskId: Integer); virtual;
end;
方法体只是占位 — 它们的存在只是为了让编译器为其生成 RTTI。实际工作发生在 OnRequest 中,由扫描器从每个方法名(ListTasks、CreateTask、GetTask…)派生的 operationId 进行分派。
在启动时将类交给扫描器,并将生成的规范加载到服务器中:
uses
sgcHTTP_OpenAPI_Server_CodeFirst, sgcHTTPServer_OpenAPI;
var
oScanner: TsgcOpenAPICodeFirstScanner;
oServer: TsgcHTTPServer_OpenAPI;
vSpec: string;
begin
oScanner := TsgcOpenAPICodeFirstScanner.Create;
try
vSpec := oScanner.GenerateSpec(TTaskManagerService);
finally
oScanner.Free;
end;
oServer := TsgcHTTPServer_OpenAPI.Create(nil);
oServer.LoadFromString(vSpec);
oServer.Bindings.Add.Port := 8081;
oServer.OnRequest := MyOnRequest;
oServer.Active := True;
end;
这些属性涵盖了常见的元数据:sgcServiceContract 填充 OpenAPI 的 info 块,sgcRoute 在类级或方法级设置路径,sgcHttpGet / Post / Put / Delete / Patch / Head / Options 选择动词,sgcSummary 和 sgcDescription 为操作编写文档,sgcTag 在 Swagger UI 中对其进行分组,sgcResponse(code, description) 声明每个响应,而 sgcFromPath / FromQuery / FromBody / FromHeader 与 sgcRequired 一起用于描述每个参数。
配置 — OpenAPIOptions
所有服务端配置都位于 OpenAPIOptions 之下,分为三个子选项:
oServer.OpenAPIOptions.Endpoint.BasePath := '/api';
oServer.OpenAPIOptions.Endpoint.ServeSpec := True; // /openapi.json
oServer.OpenAPIOptions.Endpoint.ServeSwaggerUI := True; // /docs
oServer.OpenAPIOptions.CORS.Enabled := True;
oServer.OpenAPIOptions.CORS.AllowOrigins := '*';
oServer.OpenAPIOptions.CORS.AllowHeaders := 'Content-Type, Authorization';
oServer.OpenAPIOptions.CORS.AllowMethods := 'GET, POST, PUT, DELETE, PATCH, OPTIONS';
oServer.OpenAPIOptions.Validation.ValidateRequest := True;
oServer.OpenAPIOptions.Validation.ValidateRequestBody := True;
oServer.OpenAPIOptions.Validation.ValidateQueryParams := True;
oServer.OpenAPIOptions.Validation.ValidatePathParams := True;
oServer.OpenAPIOptions.Validation.ValidateRequired := True;
启用验证后,每一个传入请求在到达您的处理器之前都会按照规范中声明的 JSON Schemas 进行检查 — 必填字段、类型、格式、枚举、范围。失败会触发 OnValidationError 事件,并附带错误列表和一个用于接受或拒绝该请求的标志。
事件
该组件为请求生命周期暴露了六个事件:
OnBeforeRequest: 在分派前触发;设置 Accept := False 可以用 403 Forbidden 拒绝。适用于限流、日志记录或按路由的网关。
OnAuthenticate: 在主处理器之前触发;设置 Authenticated := False 可以用 401 Unauthorized 拒绝。检查头、Cookie 或查询参数来决定。
OnValidationError: 验证失败时触发;接收错误列表。设置 Continue := False 可以用 400 Bad Request 拒绝。
OnRequest: 主分派事件。查看 aOperationId,将响应写入 aContext.Response,设置 Handled := True。
OnAfterRequest: 在处理器返回后触发 — 非常适合做指标统计或审计日志。
OnException: 如果有未处理的异常从您的处理器中冒出,则触发此事件。如果您希望返回 500 Internal Server Error 以外的内容,请调整 aResponseCode。
演示
sgcOpenAPI 2026.6 附带两个完整的演示,二者都仅使用新的独立组件 — 无需安装 sgcWebSockets:
- Demos/30.Server/01.CodeFirst — 一个完全使用 Delphi 类上的属性来定义的 Task Manager API。
- Demos/30.Server/02.SpecFirst — 经典的 Petstore 示例,由
petstore.json提供服务。
升级
如果您当前结合 sgcWebSockets 使用 TsgcWSServer_API_OpenAPI,则不会有任何变化 — 类、属性和事件全部保留,并且实现现在委托给与新独立组件相同的共享引擎。您可以保持现有代码原样,或者一次一个窗体地迁移到 TsgcHTTPServer_OpenAPI,以去除对 sgcWebSockets 的依赖。
sgcOpenAPI 2026.6 将于六月在下载页面提供。
有问题、反馈或需要迁移帮助?联系我们 — 您将得到编写这些代码的人的回复。
