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つの要素をまとめて提供します:
- 組み込みHTTPサーバー(Indyベース)、通常の
Bindings、Port、Activeプロパティを備えています。 - OpenAPIエンジン: スペック解析、
{paramName}セグメントによるパステンプレートルーティング、JSON-Schemaバリデーション、CORS、例外処理。 - 2つの自動配信エンドポイント:
/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;
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.Code、Response.ContentType、Response.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 (ListTasks、CreateTask、GetTask…)によってディスパッチされる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は動詞を選択し、sgcSummaryとsgcDescriptionは操作をドキュメント化し、sgcTagはSwagger UIでグループ化し、sgcResponse(code, description)は各応答を宣言し、sgcFromPath / FromQuery / FromBody / FromHeaderはsgcRequiredと組み合わせて各パラメータを記述します。
設定 — 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のインストールは不要です:
- Demos/30.Server/01.CodeFirst — Delphiクラスの属性のみで定義されたTask Manager API。
- Demos/30.Server/02.SpecFirst —
petstore.jsonから提供される定番のPetstoreの例。
アップグレード
現在sgcWebSocketsでTsgcWSServer_API_OpenAPIを使用している場合、何も変わりません — クラス、プロパティ、イベントはすべて保持され、実装は新しいスタンドアロンコンポーネントを支える同じ共有エンジンに委譲されるようになりました。既存のコードをそのまま維持することも、フォームを1つずつTsgcHTTPServer_OpenAPIに移行してsgcWebSocketsへの依存を解消することもできます。
sgcOpenAPI 2026.6は6月にダウンロードページで入手できるようになります。
ご質問、フィードバック、移行の支援が必要な場合 お問い合わせください — コードを書いた本人から返信があります。
