Delphi 的 OpenAPI 服务器

TsgcWSAPIServer_OpenAPI 提供你加载的 OpenAPI 3.x 文档服务,对照它匹配每一个传入的请求,在你的处理程序运行之前完成请求校验,并从同一个端口发布该文档和一个 Swagger UI 页面。一个 Delphi 组件,挂接到一个 TsgcHTTPServer 上。

OpenAPI 3.0 与 3.1
HTTP/2 + TLS 1.3
Swagger UI 位于 /docs
Spec-first 或 Code-first

TsgcWSAPIServer_OpenAPI

一个 Delphi 组件,把 OpenAPI 文档变成一个运行中、经过校验、自文档化的 REST 服务器。

组件类

TsgcWSAPIServer_OpenAPI,声明在 sgcWebSocket_Server_API_OpenAPI 单元中

宿主服务器

Server 赋值为一个 TsgcHTTPServerTsgcHTTPRESTServerTsgcWebSocketHTTPServer。端口、绑定和 TLS 都由宿主服务器负责。

规范格式

OpenAPI 3.0 和 3.1 文档,通过 LoadFromFileLoadFromString 以 JSON 形式读取

两种工作方式

从已有的文档走规范优先,或者从带特性标注的 Delphi 类走代码优先。代码优先需要 Delphi XE7 或更高版本。

版本

随 sgcOpenAPI 一起提供。在 sgcWebSockets 中属于 Enterprise 版本,位于 SGC OpenAPI 面板页。

内置端点

/openapi.json 提供文档,/docs 提供 Swagger UI,两者都在 OpenAPIOptions.Endpoint 中开启

Spec-first 或 Code-first,由你选择

同一个组件支持两种模式。从一份 JSON 契约开始,或者在 Delphi 中描述 API,让扫描器为你生成文档。

1. Spec-first

加载 petstore.json,用 LoadFromFile,在 OnRequest 内部按 operation id 分发,然后开始服务。路由、路径与查询参数绑定以及校验全部来自契约,你只需要编写业务逻辑。

最适合:拥有共享设计契约的团队、API-led 集成,或者将规范作为真理之源的多语言后端。

2. Code-first

sgcServiceContractsgcRoutesgcHttpGet 以及 sgcFromPath / sgcFromQuery / sgcFromBody 参数特性标注一个普通的 Delphi 类。TsgcOpenAPICodeFirstScanner.GenerateSpec 会根据类的 RTTI 构建 OpenAPI 文档,你把它交给 LoadFromString,同一个 /openapi.json 端点就会发布它。

最适合:快速原型设计、内部服务,或将现有的 TIdHTTPServer / DataSnap REST 接口迁移到自文档化的 API。

20 行代码搞定一个可工作的服务器

创建组件,加载一份文档,把它挂接到一个 HTTP 服务器上。这就是全部配置。

Delphi
uses
  sgcHTTP_Server, sgcHTTP_OpenAPI_Server, sgcWebSocket_Server_API_OpenAPI;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FServer := TsgcHTTPServer.Create(Self);
  FServer.Port := 8080;

  FOpenAPI := TsgcWSAPIServer_OpenAPI.Create(Self);
  FOpenAPI.LoadFromFile('petstore.json');      // any OpenAPI 3.x document
  FOpenAPI.OpenAPIOptions.Endpoint.ServeSpec := True;
  FOpenAPI.OpenAPIOptions.Endpoint.ServeSwaggerUI := True;
  FOpenAPI.OnRequest := OpenAPIRequest;
  FOpenAPI.Server := FServer;                // Server is the switch, there is no Active

  FServer.Active := True;
end;

// one event, dispatched by operation id
procedure TForm1.OpenAPIRequest(Sender: TObject;
  const aOperationId: string;
  const aContext: TsgcOpenAPIServerContext;
  var Handled: Boolean);
begin
  Handled := True;
  if aOperationId = 'getPetById' then
    aContext.RespondJSON(200, FPets.Values[aContext.PathParamAsString('petId')])
  else
    Handled := False;
end;

开箱即得的功能: GET /pets/{petId} 会到达上面的处理程序,此时 aOperationIdgetPetByIdGET /openapi.json 返回你加载的文档, GET /docs 打开 Swagger UI。 OpenAPIOptions.Endpoint.BasePath 可以把整个接口移到某个前缀之下,TLS 和 HTTP/2 都由宿主服务器提供。

在 OpenAPI 文档中声明的参数会通过单一的类型化上下文读取并转换。开启校验后,错误的类型会在你的处理程序运行之前就返回 400 Bad Request

Delphi
// spec snippet
//   /pets:
//     get:
//       operationId: listPets
//       parameters:
//         - name: limit       in: query    schema: { type: integer, maximum: 100 }
//         - name: status      in: query    schema: { type: string, enum: [available, pending, sold] }
//         - name: X-Tenant-Id in: header   required: true

procedure TForm1.HandleListPets(const aContext: TsgcOpenAPIServerContext);
var
  vLimit:  Integer;
  vStatus: string;
  vTenant: string;
begin
  vLimit  := aContext.QueryParamAsInteger('limit', 20);        // default 20
  vStatus := aContext.QueryParamAsString ('status', 'available');
  vTenant := aContext.HeaderValue        ('X-Tenant-Id');   // required in the spec

  aContext.RespondJSON(200, PetRepo.List(vTenant, vStatus, vLimit));
end;

在处理程序运行前完成 Schema 校验

每一个传入的请求都会对照文档声明的 schema 进行检查。校验失败时会返回一份 RFC 7807 风格的问题文档,列出每一项错误,并且除非你特意允许,否则请求不会到达你的处理程序。

检查哪些内容

typerequiredpropertiesadditionalPropertiesenumconstminLength / maxLengthpatternminimum / maximum 及其排他形式,multipleOfitemsminItems / maxItemsuniqueItemsnullablenot,以及 oneOf / anyOf / allOfformat 关键字会对 datedate-timeemailipv4uriuuid 强制执行。

选择校验范围

Validation.ValidateRequest 是总开关,单独打开就会校验所有范围。用 ValidateRequestBodyValidateQueryParamsValidatePathParamsValidateHeaderParamsValidateCookieParams 来缩小范围。无论选择哪个范围,EnforceRequired 始终生效。

由你做最终决定

OnValidationError 会把 operation id 和完整的失败列表交给你。它的 Continue 标志到达时是 False,所以除非你特意把它设为 True,否则请求会被拒绝。加载完成后,Validation.Warnings 会列出文档中用到但未被强制执行的每一个 schema 关键字,空列表就意味着没有遗漏。

JSON,引擎实际写出的 400 响应
{
  "type":   "about:blank",
  "title":  "Bad Request",
  "status": 400,
  "detail": "Request validation failed",
  "errors": [
    "/email: invalid email format",
    "/age: must be <= 120",
    "/status: value not in enum"
  ]
}

由规范驱动的认证方案

Security.EnforceSecurity 设为开启后,文档声明的 securitySchemes 就会应用到传入的请求上。你只需编写凭据查找逻辑,组件负责解析请求,并在查找结果为否时返回 401 或 403。

API Key

从 header、查询参数或 cookie 中读取,具体取决于该方案的声明。OnValidateAPIKey 会收到方案、名称、位置和 key,并通过 Valid 返回结果。

HTTP Basic

Authorization 请求头已经替你解析好。OnValidateBasic 会收到用户名和密码,并通过 Valid 返回结果。凭据永远不会写入日志。

Bearer 与 JWT

Security.JWTSecret 用于验证令牌。原样使用即视为 HMAC 密钥,包含 -----BEGIN 的值则视为 PEM 公钥。ValidateExpirationIssuerAudience 会检查这些声明。

自定义校验器

JWTSecret 留空,令牌就只会检查是否存在,这样 OnValidateBearer 就可以把它交给你自己的令牌服务,并通过 Valid 返回结果。

401 还是 403

校验失败的请求会返回 401,如果请求已经通过身份验证只是权限不够,则返回 403。OnAuthenticate 最先运行,一旦你清除 Authenticated,就会以 401 拒绝请求。

在代码写好之前先模拟

Mock.Enabled 会用文档自带的示例和 schema,为一个还没有处理程序的操作生成响应,并附带 Mock.StatusCode,这样前端团队就能在实现完成之前先动手。

Delphi,用你自己的代码校验 bearer 令牌
FOpenAPI.OpenAPIOptions.Security.EnforceSecurity := True;
FOpenAPI.OpenAPIOptions.Security.JWTSecret := GetSecretFromEnvironment;
FOpenAPI.OpenAPIOptions.Security.ValidateExpiration := True;
FOpenAPI.OpenAPIOptions.Security.Issuer   := 'https://auth.example.com';
FOpenAPI.OpenAPIOptions.Security.Audience := 'api.example.com';
FOpenAPI.OnValidateBearer := OpenAPIValidateBearer;

procedure TForm1.OpenAPIValidateBearer(Sender: TObject;
  const aToken: string;
  const aContext: TsgcOpenAPIServerContext; var Valid: Boolean);
begin
  Valid := MyTokenService.Verify(aToken);
end;

内置 Swagger UI

无需外部依赖、无需 Node.js,部署流程中也不必构建文档。组件会自己生成这个页面,并读取你的服务器实际提供的文档。

/openapi.json

你加载的文档,在 Endpoint.ServeSpec 开启时提供服务,始终与服务器实际路由的内容保持一致。把任何客户端生成器指向这个 URL 都可以,包括 sgcOpenAPI。

/docs

交互式 Swagger UI 页面,在 Endpoint.ServeSwaggerUI 开启时提供服务。可以试用操作、浏览 schema、查看示例,全部数据都来自你正在运行的服务器。

可固定版本,也可完全离线

该页面默认从公共 CDN 加载 CSS 和 JavaScript。Endpoint.SwaggerUIBaseURL 可以固定版本,Endpoint.SwaggerUIAssetsPath 则可以让 swagger-ui.cssswagger-ui-bundle.js 从本地目录提供服务,这样即使在完全离线的机器上也能工作。

一切都在 OpenAPIOptions 之下

五个持久化的子对象,全部可见于对象检查器,也都可以在运行时赋值。

Endpoint

BasePath 会给每个路由和两个内置端点都加上前缀。ServeSpecServeSwaggerUI 用于开关它们。SpecFile 是懒加载的,只会在既不是这两者的第一个请求上加载,所以当文档必须从第一次调用起就完整时,请使用 LoadFromFile

Validation

ValidateRequest 加上五个范围开关,以及 EnforceRequired。每次加载后,Warnings 会报告文档用到但该校验器未强制执行的 schema 关键字。

CORS

EnabledAllowOriginsAllowHeadersAllowMethods。引擎只在其文档拥有的路径上盖这些响应头,所以要给宿主服务器拥有的路径设置相同的值。

Security

EnforceSecurityJWTSecretValidateExpirationIssuerAudience。内置检查无法判定的一切都会交给 OnValidateAPIKeyOnValidateBasicOnValidateBearer

Mock

EnabledStatusCode。没有处理程序的操作会用文档自带的示例和 schema 来回答,这样契约在实现完成之前也能调用。

特意保留的 Not Implemented

Handled 留在 False,引擎就会返回 501 Not Implemented 并指明该操作,而不是看起来像路由出错的 404。

一个 HTTP 服务器,多种接口

TsgcWSAPIServer_OpenAPI 挂接到承载你的 WebSocket 端点、AI/LLM 流和静态文件的同一个 sgcWebSockets HTTP 服务器上。一个端口、一份 TLS 证书、一条日志流。

Server 就是开关

这里没有 Active 属性。给 Server 赋值就会挂接组件,把它设为 nil 就会分离,宿主服务器全程保持运行不受影响。分离之后,其文档拥有的路径会直接落到你原来的处理程序上。

它绝不会接管服务器

每个请求都会先交给这个组件,它只回答其文档声明的路径。其余的请求照旧到达 OnCommandGet,所以一个契约优先的区域可以和手写的路由以及 DocumentRoot 提供的静态内容共存于同一个端口上。

宿主的 TLS 和 HTTP/2

端口、绑定、证书和 HTTP/2 协商都属于宿主服务器,所以 REST 接口会原样继承它们。把它挂接到一个 TsgcHTTPRESTServer 上,该服务器的 CORS、指标、健康检查和租户功能也同样适用。

典型部署

公开 REST API

带版本、契约测试,自动生成的 SDK 可供客户从 /openapi.json 下载。

内部微服务

能挺过重构的服务间契约 — 规范就是集成测试。

工业 / 物联网网关

边缘设备从同一个 Delphi 二进制文件中既暴露文档化的 REST 控制面,又暴露 MQTT 或 WebSocket 遥测接口。

Webhook 接收端

每个供应商的 webhook 载荷都变成类型化的 Pascal 记录 — Stripe、GitHub、Twilio、Slack — 内置校验与幂等性。

遗留系统现代化

在不重写业务逻辑的前提下,把老旧的 DataSnap 或 RemObjects 后端包装在干净的 OpenAPI 接口之后。

BFF(Backend-for-Frontend)

把两三个上游 API 聚合到一份贴合消费者形态的规范背后 — 你的 SPA 或移动 App 只与一个类型化的端点对话。

搭配使用

OpenAPI Parser

把任意外部规范加载到与服务器使用的同一模型中 — 相同的校验、相同的类型系统、相同的安全原语。

预构建的云 SDK

1,195+ 个为 AWS、Azure、GCP、Stripe、GitHub、Kubernetes 等生成的 SDK — 你的服务器可以用同一族组件调用任何一个。

sgcWebSockets

WebSocket、MQTT、AMQP、WebRTC、AI/LLM、IoT — HTTP 服务器能与你的 REST 接口一同承载的一切。

sgcSign

用 XAdES / PAdES / CAdES 对请求和响应体进行签名,面向受监管行业 — 每个操作都具有 eIDAS 级别的完整性。

超值之选:All-AccesseSeGeCe 全部产品,含高级支持,每年 €1,059 起。
查看 All-Access 价格

几分钟内构建你的第一个 OpenAPI 服务器

下载免费试用版。完整的服务器、两套 UI、所有认证方案 — 没有功能限制,评估期间也没有时间炸弹。