Die nächste Version von sgcOpenAPI, Version 2026.6, geplant für Juni, liefert einen OpenAPI 3.0-Server, den du hosten kannst, ohne sgcWebSockets zu installieren. Zwei Komponenten übernehmen das: TsgcHTTPServer, der Indy-basierte HTTP-Server, und TsgcWSAPIServer_OpenAPI, die API-Komponente, die du an ihn hängst. Richte die API-Komponente auf eine Spezifikation (oder generiere eine aus einer Delphi-Klasse mit RTTI-Attributen), weise ihre Server-Eigenschaft zu, starte den HTTP-Server, und du hast eine dokumentierte REST-API mit automatisch bereitgestellter Swagger UI.
Die wichtigste Neuerung ist, dass sgcOpenAPI sgcWebSockets nicht mehr benötigt, um einen HTTP-Server zu hosten. Beide Komponenten werden vollständig aus sgcOpenAPI ausgeliefert, paketiert und installiert. Wenn du sgcWebSockets bereits verwendest, funktioniert die dir bekannte Komponente TsgcWSServer_API_OpenAPI unverändert weiter, weil es dieselbe Klasse ist: Beide Produkte bauen sie aus derselben Engine.
Was du bekommst
Das Paar bringt drei Dinge mit:
- Einen HTTP-Server (auf Indy-Basis),
TsgcHTTPServer, mit den üblichen EigenschaftenBindings,PortundActive. - Die OpenAPI-Engine: Spezifikations-Parsing, Pfad-Vorlagen-Routing mit
{paramName}-Segmenten, JSON-Schema-Validierung, CORS, Ausnahmebehandlung. - Zwei automatisch bereitgestellte Endpunkte: die Spezifikation unter
/openapi.jsonund eine Swagger UI unter/docs. Beide sind standardmäßig aktiv und können inOpenAPIOptions.Endpointumgeschaltet werden.
Schnellstart — das minimale Beispiel
Das ist alles, was du brauchst, um einen funktionierenden OpenAPI-Server mit Swagger UI zu hosten. Beachte, dass die API-Komponente keine eigene Active-Eigenschaft hat: Das Zuweisen von Server hängt sie an, und das Zuweisen von nil hängt sie ab, während der HTTP-Server weiterläuft.
uses
sgcHTTP_Server, sgcWebSocket_Server_API_OpenAPI;
var
oServer: TsgcHTTPServer;
oOpenAPI: TsgcWSAPIServer_OpenAPI;
begin
oServer := TsgcHTTPServer.Create(nil);
oOpenAPI := TsgcWSAPIServer_OpenAPI.Create(nil);
try
oServer.Bindings.Add.Port := 8080;
oOpenAPI.LoadFromFile('petstore.json');
oOpenAPI.OnRequest := MyOnRequest;
oOpenAPI.Server := oServer;
oServer.Active := True;
Readln;
finally
oOpenAPI.Free;
oServer.Free;
end;
end;
Rufe http://localhost:8080/docs für die Swagger UI und http://localhost:8080/openapi.json für die Spezifikation auf. Jede in der Spezifikation definierte Operation wird mit der aufgelösten operationId und einem vollständig aufgebauten Anfragekontext an deinen MyOnRequest-Handler weitergeleitet.
Spec-First — eine vorhandene OpenAPI-3.0-Datei laden
Wenn du bereits eine OpenAPI-3.0-Datei in JSON hast (Petstore, einen internen API-Vertrag, ein öffentliches Schema, das du mocken möchtest), ist Spec-First der schnellste Weg, sie bereitzustellen. LoadFromFile liest und parst die Spezifikation, erstellt eine Routing-Tabelle aus dem Abschnitt paths und vergleicht jede eingehende Anfrage damit. Der Server liest JSON, konvertiere einen YAML-Vertrag also vorher, zum Beispiel mit sgcOpenAPI.exe.
Die operationId jeder Route ist der Dispatch-Schlüssel. Innerhalb von OnRequest behandelst du jede Operation der Reihe nach:
uses
sgcHTTP_Server, sgcHTTP_OpenAPI_Server,
sgcHTTP_OpenAPI_Server_Engine, sgcWebSocket_Server_API_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;
Der TsgcOpenAPIServerContext bietet dir typisierte Accessor-Methoden für alles in der Anfrage: PathParamAsString / PathParamAsInteger für Vorlagensegmente, QueryParamAsString / QueryParamAsInteger / QueryParamAsBoolean mit Standardwerten, BodyAsString / BodyAsJSON für den Anfragerumpf und HeaderValue für jeden eingehenden Header. Zum Antworten verwendest du die Hilfsmethoden RespondJSON(code, content) und RespondError(code, title, detail) oder setzt Response.Code, Response.ContentType und Response.Content direkt für volle Kontrolle.
Code-First — die Spezifikation aus einer Delphi-Klasse generieren
Wenn du den API-Vertrag lieber in Delphi schreiben und die Spezifikation generieren lassen möchtest, dekoriere eine Klasse mit RTTI-Attributen. TsgcOpenAPICodeFirstScanner durchläuft die Klasse, erstellt ein vollständiges OpenAPI-3.0-JSON-Dokument, und du lädst dieses mit LoadFromString in den Server. Dies erfordert Delphi XE7 oder neuer (für erweitertes 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;
Die Methodenrümpfe sind Stubs — sie existieren nur, damit der Compiler RTTI für sie ausgibt. Die eigentliche Arbeit erfolgt in OnRequest, dispatched anhand der operationId, die der Scanner aus jedem Methodennamen ableitet (ListTasks, CreateTask, GetTask…).
Übergib die Klasse beim Start an den Scanner und lade die generierte Spezifikation in den Server:
uses
sgcHTTP_Server, sgcHTTP_OpenAPI_Server_CodeFirst,
sgcWebSocket_Server_API_OpenAPI;
var
oScanner: TsgcOpenAPICodeFirstScanner;
oServer: TsgcHTTPServer;
oOpenAPI: TsgcWSAPIServer_OpenAPI;
vSpec: string;
begin
oScanner := TsgcOpenAPICodeFirstScanner.Create;
try
vSpec := oScanner.GenerateSpec(TTaskManagerService);
finally
oScanner.Free;
end;
oServer := TsgcHTTPServer.Create(nil);
oServer.Bindings.Add.Port := 8081;
oOpenAPI := TsgcWSAPIServer_OpenAPI.Create(nil);
oOpenAPI.LoadFromString(vSpec);
oOpenAPI.OnRequest := MyOnRequest;
oOpenAPI.Server := oServer;
oServer.Active := True;
end;
Die Attribute decken die üblichen Metadaten ab: sgcServiceContract füllt den OpenAPI-Block info, sgcRoute legt den Pfad auf Klassen- oder Methodenebene fest, sgcHttpGet / Post / Put / Delete / Patch / Head / Options wählt das Verb aus, sgcSummary und sgcDescription dokumentieren die Operation, sgcTag gruppiert sie in der Swagger UI, sgcResponse(code, description) deklariert jede Antwort, und sgcFromPath / FromQuery / FromBody / FromHeader zusammen mit sgcRequired beschreiben jeden Parameter.
Konfiguration — OpenAPIOptions
Die gesamte serverseitige Konfiguration befindet sich unter OpenAPIOptions auf der API-Komponente, gruppiert in fünf Unter-Optionen. Diese drei enthalten die alltäglichen Einstellungen:
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;
Bei aktivierter Validierung wird jede eingehende Anfrage anhand der in der Spezifikation deklarierten JSON-Schemas geprüft, bevor sie deinen Handler erreicht: erforderliche Felder, Typen, Formate, Enums, Wertebereiche. Fehler lösen das Ereignis OnValidationError mit der Liste der Fehler und einer Markierung zum Akzeptieren oder Ablehnen der Anfrage aus.
Ereignisse
Sechs Ereignisse decken den Lebenszyklus einer Anfrage ab:
OnBeforeRequest: wird vor dem Dispatch ausgelöst; setze Accept := False, um mit 403 Forbidden abzulehnen. Nützlich für Rate-Limiting, Logging oder routenspezifische Sperren.
OnAuthenticate: wird vor dem Haupt-Handler ausgelöst; setze Authenticated := False, um mit 401 Unauthorized abzulehnen. Prüfe Header, Cookies oder Abfrageparameter zur Entscheidung.
OnValidationError: wird ausgelöst, wenn die Validierung fehlschlägt; erhält die Liste der Fehler. Setze Continue := False, um mit 400 Bad Request abzulehnen.
OnRequest: das zentrale Dispatch-Ereignis. Sieh dir aOperationId an, schreibe die Antwort in aContext.Response, setze Handled := True.
OnAfterRequest: wird nach Rückkehr des Handlers ausgelöst — ideal für Metriken oder Audit-Logging.
OnException: wird ausgelöst, wenn eine unbehandelte Ausnahme aus deinem Handler heraussprudelt. Passe aResponseCode an, wenn du etwas anderes als 500 Internal Server Error wünschst.
Die beiden verbleibenden Unter-Optionen bringen ihre eigenen: Security steuert OnValidateAPIKey, OnValidateBasic und OnValidateBearer für die securitySchemes, die die Spezifikation deklariert, und Mock beantwortet eine Operation ohne Handler aus den eigenen Beispielen der Spezifikation.
Demos
Mit sgcOpenAPI 2026.6 werden zwei vollständige Demos ausgeliefert, beide gehostet vom eigenständigen Paar, sodass keine sgcWebSockets-Installation erforderlich ist:
- Demos/30.Server/01.OpenAPI_Server_CodeFirst, eine Task-Manager-API, die vollständig mit Attributen auf einer Delphi-Klasse definiert ist.
- Demos/30.Server/02.OpenAPI_Server_SpecFirst, das klassische Petstore-Beispiel, bereitgestellt aus
petstore.json.
Upgrade
Wenn du derzeit TsgcWSServer_API_OpenAPI mit sgcWebSockets verwendest, ändert sich nichts. Die Klasse, ihre Eigenschaften und ihre Ereignisse bleiben alle erhalten, und die Implementierung delegiert an die gemeinsame Engine. TsgcWSAPIServer_OpenAPI ist der veröffentlichte Nachfahre derselben Klasse, sodass sgcOpenAPI nur ändert, woher das Paket kommt.
sgcOpenAPI 2026.6 wird im Juni auf der Download-Seite verfügbar sein.
Fragen, Feedback oder Migrationshilfe? Nimm Kontakt auf, du bekommst eine Antwort von den Personen, die den Code geschrieben haben.
