sgcOpenAPI 2026.6 — スタンドアロンOpenAPIサーバー、スペックファーストまたはコードファースト

· リリース

sgcOpenAPIの次期リリース — 6月に予定されているバージョン2026.6 — では、まったく新しいコンポーネントTsgcHTTPServer_OpenAPIが提供されます。これは、組み込みHTTPサーバーでOpenAPI 3.0サービスをホストする、単一で自己完結型のDelphiコンポーネントです。フォームに配置し、スペックを指定する(またはRTTI属性を持つDelphiクラスから生成する)か、Active := Trueを設定すれば、自動配信されるSwagger UIを備えたドキュメント付きREST APIが完成します。

目玉となる変更点は、sgcOpenAPIがHTTPサーバーをホストするためにsgcWebSocketsを必要としなくなったことです。新しいコンポーネントは、sgcOpenAPIから完全に出荷、パッケージ化、インストールされます。すでにsgcWebSocketsを使用している場合、以前のTsgcWSServer_API_OpenAPIコンポーネントは変更なく引き続き動作します — 両者は内部的に同じエンジンを共有しています。

1つのコンポーネントで得られるもの

TsgcHTTPServer_OpenAPIは3つの要素をまとめて提供します:

クイックスタート — 最小限の例

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;

Swagger UIにはhttp://localhost:8080/docs、スペックにはhttp://localhost:8080/openapi.jsonにアクセスしてください。スペックで定義されたすべての操作は、解決されたoperationIdと完全に構築されたリクエストコンテキストを伴ってMyOnRequestハンドラーにルーティングされます。

スペックファースト — 既存のOpenAPI 3.0ファイルを読み込む

既存のOpenAPI 3.0 JSONまたはYAMLファイル(Petstore、社内APIコントラクト、モック化したい公開スキーマなど)がある場合、スペックファーストはそれを提供する最速の方法です。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.CodeResponse.ContentTypeResponse.Contentを直接設定します。

コードファースト — 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を生成するためだけに存在します。実際の処理は、スキャナーが各メソッド名から導出する operationId (ListTasksCreateTaskGetTask…)によってディスパッチされるOnRequest内で行われます。

起動時にクラスをスキャナーに渡し、生成されたスペックをサーバーに読み込みます:

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は動詞を選択し、sgcSummarysgcDescriptionは操作をドキュメント化し、sgcTagはSwagger UIでグループ化し、sgcResponse(code, description)は各応答を宣言し、sgcFromPath / FromQuery / FromBody / FromHeadersgcRequiredと組み合わせて各パラメータを記述します。

設定 — OpenAPIOptions

すべてのサーバーサイド設定はOpenAPIOptionsの下にあり、3つのサブオプションにグループ化されています:

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スキーマに対してチェックされます — 必須フィールド、型、フォーマット、列挙、範囲。失敗するとエラー一覧とリクエストを受け入れるか拒否するかのフラグを伴ってOnValidationErrorイベントが発生します。

イベント

コンポーネントはリクエストのライフサイクル用に6つのイベントを公開しています:

OnBeforeRequest: ディスパッチ前に発生します。Accept := Falseを設定すると403 Forbiddenで拒否されます。レート制限、ロギング、またはルートごとのゲートに便利です。

OnAuthenticate: メインハンドラーの前に発生します。Authenticated := Falseを設定すると401 Unauthorizedで拒否されます。ヘッダー、クッキー、またはクエリパラメータを検査して判断します。

OnValidationError: バリデーションが失敗したときに発生し、エラー一覧を受け取ります。Continue := Falseを設定すると400 Bad Requestで拒否されます。

OnRequest: メインディスパッチイベント。aOperationIdを見て、aContext.Responseに応答を書き込み、Handled := Trueを設定します。

OnAfterRequest: ハンドラーが戻った後に発生します — メトリクスや監査ロギングに最適です。

OnException: ハンドラーから処理されない例外が発生した場合に発生します。500 Internal Server Error以外を返したい場合はaResponseCodeを調整します。

デモ

sgcOpenAPI 2026.6には2つの完全なデモが同梱されており、どちらも新しいスタンドアロンコンポーネントのみを使用します — sgcWebSocketsのインストールは不要です:

アップグレード

現在sgcWebSocketsでTsgcWSServer_API_OpenAPIを使用している場合、何も変わりません — クラス、プロパティ、イベントはすべて保持され、実装は新しいスタンドアロンコンポーネントを支える同じ共有エンジンに委譲されるようになりました。既存のコードをそのまま維持することも、フォームを1つずつTsgcHTTPServer_OpenAPIに移行してsgcWebSocketsへの依存を解消することもできます。

sgcOpenAPI 2026.6は6月にダウンロードページで入手できるようになります。

ご質問、フィードバック、移行の支援が必要な場合 お問い合わせください — コードを書いた本人から返信があります。