Delphi 用 OpenAPI サーバー

TsgcWSAPIServer_OpenAPI は、読み込んだ OpenAPI 3.x ドキュメントを配信し、受信するすべてのリクエストをそのドキュメントと照合し、ハンドラーが動く前にリクエストを検証し、同じポートからドキュメントと Swagger UI ページを公開します。1 つの Delphi コンポーネントを TsgcHTTPServer にアタッチするだけです。

OpenAPI 3.0 および 3.1
HTTP/2 + TLS 1.3
/docs で Swagger UI
Spec-first または Code-first

TsgcWSAPIServer_OpenAPI

OpenAPI ドキュメントを、稼働中で検証済み、自己文書化された REST サーバーに変える 1 つの Delphi コンポーネント。

コンポーネントクラス

TsgcWSAPIServer_OpenAPIsgcWebSocket_Server_API_OpenAPI で宣言されています

ホストサーバー

ServerTsgcHTTPServerTsgcHTTPRESTServer、または TsgcWebSocketHTTPServer を割り当てます。ポート、バインディング、TLS はホストが管理します。

仕様フォーマット

OpenAPI 3.0 と 3.1 のドキュメントを、LoadFromFileLoadFromString で JSON として読み込みます

2 つのワークフロー

すでに手元にあるドキュメントから始めるスペックファースト、または属性付きの Delphi クラスから始めるコードファースト。コードファーストには Delphi XE7 以降が必要です。

エディション

sgcOpenAPI に同梱されます。sgcWebSockets の中では Enterprise エディションに属し、SGC OpenAPI パレットページにあります。

組み込みエンドポイント

ドキュメント用の /openapi.json と Swagger UI 用の /docs。どちらも OpenAPIOptions.Endpoint でオンになります

Spec-first か Code-first か、選ぶのはあなたです

同じコンポーネントがどちらのモードでも動作します。JSON コントラクトから始めるか、Delphi で API を記述してスキャナーにドキュメントを生成させるか、どちらでも構いません。

1. Spec-first

LoadFromFilepetstore.json を読み込み、OnRequest の中で operation id に応じて振り分け、配信を開始します。ルーティング、パスおよびクエリパラメータのバインディング、検証はすべてコントラクトから得られるので、書くのはビジネスロジックだけです。

最適なケース:共有のデザインコントラクトを持つチーム、API-led な統合、または仕様が信頼の源泉となるポリグロットなバックエンド。

2. Code-first

素の Delphi クラスに sgcServiceContractsgcRoutesgcHttpGet と、パラメータ用の sgcFromPath / sgcFromQuery / sgcFromBody 属性を付けます。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} は、aOperationIdgetPetById に設定された状態で上記のハンドラーに届き、 GET /openapi.json は読み込んだドキュメントを返し、 GET /docs は Swagger UI を開きます。 OpenAPIOptions.Endpoint.BasePath を使えば、この面全体を任意のプレフィックスの下へ移せます。TLS と HTTP/2 はホストサーバーから引き継がれます。

Path、Query、Header、Cookie パラメータ、すべて型付き

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;

ハンドラーが動く前のスキーマ検証

受信するすべてのリクエストは、ドキュメントが宣言するスキーマと照合されます。失敗した場合は、各エラーを列挙した RFC 7807 形式の problem ドキュメントで応答し、あなたが明示的に許可しない限りハンドラーには届きません。

検証される項目

typerequiredpropertiesadditionalPropertiesenumconstminLength / maxLengthpattern、排他形式を含む minimum / maximummultipleOfitemsminItems / maxItemsuniqueItemsnullablenot、そして oneOf / anyOf / allOfformat キーワードは datedate-timeemailipv4uriuuid に対して強制されます。

検証範囲を選ぶ

Validation.ValidateRequest がマスタースイッチで、これ単独ですべての範囲を検証します。ValidateRequestBodyValidateQueryParamsValidatePathParamsValidateHeaderParamsValidateCookieParams で範囲を絞り込めます。EnforceRequired は、選んだどの範囲でも有効なままです。

最終判断はあなたに

OnValidationError は、オペレーション ID と失敗の全リストを渡します。その Continue フラグは False の状態で届くため、あなたが明示的に True に設定しない限りリクエストは拒否されます。読み込みのあとには、Validation.Warnings が、ドキュメントが使っていて強制されていないスキーマキーワードをすべて列挙するので、リストが空であれば見落としがないことになります。

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

スキームが宣言するとおりに、ヘッダー、クエリパラメータ、または cookie から読み取ります。OnValidateAPIKey はスキーム、名前、位置、キーを受け取り、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 は、ハンドラーがないオペレーションに対して、ドキュメント自身の例とスキーマから Mock.StatusCode で応答するため、実装を書いている間もフロントエンドチームが作業を進められます。

Delphi、独自コードでベアラートークンを検証
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 がオンのときに配信します。オペレーションを試し、スキーマを閲覧し、例を読めます。すべて実際に稼働しているサーバーから供給されます。

バージョン固定、または完全オフライン

ページは既定で公開 CDN から CSS と JavaScript を読み込みます。Endpoint.SwaggerUIBaseURL でバージョンを固定でき、Endpoint.SwaggerUIAssetsPath を使えば swagger-ui.cssswagger-ui-bundle.js をローカルフォルダから配信できるので、外部ネットワークに接続できないマシンでも動作します。

すべてが OpenAPIOptions の下にある

5 つの永続的なサブオブジェクトで、すべてオブジェクトインスペクターに表示され、すべて実行時に割り当てられます。

Endpoint

BasePath は、すべてのルートと 2 つの組み込みエンドポイントの両方にプレフィックスを付けます。ServeSpecServeSwaggerUI でそれぞれを切り替えます。SpecFile は、どちらでもない最初のリクエストの時点で遅延読み込みされるため、ドキュメントを最初の呼び出しから確実に用意しておきたい場合は LoadFromFile を使ってください。

Validation

ValidateRequest と、5 つの範囲スイッチ、そして EnforceRequiredWarnings は、読み込みのたびに、この検証器が強制していないドキュメント中のスキーマキーワードを報告します。

CORS

EnabledAllowOriginsAllowHeadersAllowMethods。エンジンは自身のドキュメントが所有するパスにのみ応答を付与するので、ホストサーバーが所有する残りのパスには、ホスト側で同じ値を設定してください。

Security

EnforceSecurityJWTSecretValidateExpirationIssuerAudience。組み込みのチェックだけでは判断できないものはすべて OnValidateAPIKeyOnValidateBasicOnValidateBearer に渡されます。

Mock

EnabledStatusCode。ハンドラーがないオペレーションには、ドキュメント自身の例とスキーマから応答するので、実装が完成する前からコントラクトを呼び出せます。

あえての Not Implemented

HandledFalse のままにしておくと、エンジンはルーティングミスに見える 404 ではなく、オペレーション名を添えた 501 Not Implemented で応答します。

1 つの HTTP サーバー、複数の面

TsgcWSAPIServer_OpenAPI は、WebSocket エンドポイント、AI/LLM ストリーム、静的ファイルをホストしているのと同じ sgcWebSockets HTTP サーバーにアタッチします。ポート 1 つ、TLS 証明書 1 つ、ログストリーム 1 つ。

Server がスイッチ

Active プロパティはありません。Server を割り当てるとコンポーネントがアタッチされ、nil を設定するとデタッチされます。どちらの場合もホストサーバーは動作し続けます。デタッチされると、そのドキュメントが所有するパスはそのまま通常のハンドラーに通ります。

サーバーを乗っ取らない

各リクエストはまずコンポーネントに提示され、コンポーネントはそのドキュメントが宣言するパスにのみ応答します。それ以外はすべて従来どおり OnCommandGet に届くため、コントラクトファーストの区画は、手書きのルートや DocumentRoot の静的コンテンツと同じポート上で共存できます。

ホストの TLS と HTTP/2

ポート、バインディング、証明書、HTTP/2 ネゴシエーションはホストサーバーに属しているため、REST 面はそれらをそのまま引き継ぎます。TsgcHTTPRESTServer にアタッチすれば、そのサーバーの CORS、メトリクス、ヘルス、テナンシーも適用されます。

典型的なデプロイ

パブリック REST API

バージョン管理、コントラクトテスト済み、自動生成された SDK は顧客が /openapi.json からダウンロードできます。

社内マイクロサービス

リファクタを生き延びるサービス間コントラクト — 仕様がそのまま統合テストです。

産業 / IoT ゲートウェイ

エッジデバイスが、同一の Delphi バイナリから、ドキュメント化された REST コントロールプレーンと MQTT または WebSocket のテレメトリ面を公開します。

Webhook レシーバー

各プロバイダの Webhook ペイロードが型付きの Pascal レコードになります — Stripe、GitHub、Twilio、Slack — 検証と冪等性が標準装備。

レガシーモダナイゼーション

ビジネスロジックを書き直さずに、古い DataSnap や RemObjects のバックエンドをきれいな OpenAPI 面の背後に包み込みます。

BFF(Backend-for-Frontend)

2、3 個のアップストリーム API を、消費者の形に合わせた 1 つの仕様の背後に集約 — SPA やモバイルアプリは型付きの単一エンドポイントと対話します。

相性の良い製品

OpenAPI Parser

あらゆる外部仕様を、サーバーが使うのと同じモデルにロードできます — 同じ検証、同じ型システム、同じセキュリティのプリミティブ。

ビルド済みクラウド SDK

AWS、Azure、GCP、Stripe、GitHub、Kubernetes など向けの 1,195 以上の生成済み SDK — サーバーは同じコンポーネントファミリーで、そのいずれも呼び出せます。

sgcWebSockets

WebSocket、MQTT、AMQP、WebRTC、AI/LLM、IoT — HTTP サーバーが REST 面と並べてホストできるすべて。

sgcSign

規制業界向けに、リクエストおよびレスポンスのボディに XAdES / PAdES / CAdES で署名 — どのオペレーションにも eIDAS グレードの完全性。

最もお得な選択: All-AccesseSeGeCe の全製品にプレミアムサポートが付いて、年間 €1,059 からご利用いただけます。
All-Access の価格を見る

数分で最初の OpenAPI サーバーを構築

無料試用版をダウンロード。フルサーバー、両方の UI、すべての認証スキーム — 機能制限なし、評価期間中のタイムボムもありません。