De Enterprise-editie van sgcWebSockets bevat een nieuwe component, TsgcWSAPIServer_OpenAPI, die een OpenAPI 3-beschrijving omzet in een draaiende REST-server binnen uw Delphi-toepassing. Plaats hem op een formulier, koppel hem aan een HTTP-server, geef hem een spec — en de routes, requestvalidatie, foutreacties en live Swagger UI-documentatie worden voor u bedraad. Dit artikel laat zien hoe de component werkt, op welke twee manieren u hem kunt aansturen (spec-first en code-first), welke configuratieknoppen ertoe doen, en geeft een compleet Delphi-voorbeeld dat u direct in een nieuw project kunt plakken.
Wat de component doet
TsgcWSAPIServer_OpenAPI is een lichte API-server die via het bestaande uitbreidingspunt voor API-servers in TsgcWebSocketHTTPServer wordt aangesloten. U koppelt hem aan een server, laadt een OpenAPI 3.0-specificatie, en hij doet bij elk binnenkomend HTTP-verzoek vier dingen:
- vergelijkt de URL en de HTTP-methode met de routes die in de spec gedeclareerd zijn (inclusief
{path}-parameters); - valideert het verzoek — verplichte velden, queryparameters, padparameters en request body — aan de hand van de schema's in de spec;
- vuurt een
OnRequest-event af met de gevondenoperationIden een volledig gevuld contextobject, zodat uw code alleen nog de bedrijfslogica hoeft te schrijven; - biedt out-of-the-box twee ingebouwde endpoints — de ruwe spec op
/openapi.jsonen een interactieve Swagger UI op/docs— met optionele CORS-preflight op elke route.
Het resultaat is dat de spec de enige bron van waarheid wordt: wijzig een pad, een parameter of een responscode in de JSON, herstart, en de server pikt het nieuwe contract op zonder dat u Delphi-code hoeft te hercompileren.
Spec-first: een bestaand OpenAPI 3-bestand laden
Als u al een OpenAPI 3-document hebt (bijvoorbeeld een petstore.json die u vanuit een API-designer hebt geëxporteerd) komt de bedrading neer op drie regels — component aanmaken, spec laden, server koppelen. De rest is configuratie en de OnRequest-handler die de werkelijke responses produceert.
uses
sgcWebSocket, sgcWebSocket_Classes,
sgcWebSocket_Server_API_OpenAPI,
sgcHTTP_OpenAPI_Server;
var
WSServer: TsgcWebSocketHTTPServer;
FOpenAPI: TsgcWSAPIServer_OpenAPI;
begin
WSServer := TsgcWebSocketHTTPServer.Create(nil);
WSServer.Port := 8080;
FOpenAPI := TsgcWSAPIServer_OpenAPI.Create(nil);
FOpenAPI.OnRequest := OnOpenAPIRequest;
FOpenAPI.OnBeforeRequest := OnOpenAPIBeforeRequest;
FOpenAPI.OnValidationError := OnOpenAPIValidationError;
// Configuration
FOpenAPI.OpenAPIOptions.Endpoint.ServeSpec := True;
FOpenAPI.OpenAPIOptions.Endpoint.ServeSwaggerUI := True;
FOpenAPI.OpenAPIOptions.CORS.Enabled := True;
FOpenAPI.OpenAPIOptions.Validation.ValidateRequest := True;
FOpenAPI.OpenAPIOptions.Validation.ValidateRequired := True;
FOpenAPI.OpenAPIOptions.Validation.ValidateRequestBody := True;
// Load spec and attach to server
FOpenAPI.LoadFromFile('petstore.json');
FOpenAPI.Server := WSServer;
WSServer.Active := True;
// Swagger UI: http://localhost:8080/docs
// Raw spec: http://localhost:8080/openapi.json
end;
Het OnRequest-event wordt per operationId verstuurd — de string die u naast elke operatie in de YAML/JSON hebt gezet. U schrijft één branch per operatie, leest de invoer uit de context en stuurt een respons terug:
procedure TForm1.OnOpenAPIRequest(Sender: TObject;
const aOperationId: string; const aContext: TsgcOpenAPIServerContext;
var Handled: Boolean);
var
vId: Int64;
vLimit: Integer;
begin
Handled := True;
if aOperationId = 'listPets' then
begin
vLimit := aContext.QueryParamAsInteger('limit', 100);
aContext.RespondJSON(200, BuildPetsJSON(vLimit));
end
else if aOperationId = 'getPetById' then
begin
vId := aContext.PathParamAsInteger('petId');
if FindPet(vId) then
aContext.RespondJSON(200, PetAsJSON(vId))
else
aContext.RespondError(404, 'Not Found',
Format('Pet %d not found', [vId]));
end
else
Handled := False;
end;
Het TsgcOpenAPIServerContext-object is het werkpaard van elke handler. Het stelt pad- en queryparameters op naam beschikbaar (PathParamAsString, PathParamAsInteger, QueryParamAsString, QueryParamAsInteger, QueryParamAsBoolean), headeropzoeking via HeaderValue, de body als string (BodyAsString) of voorgeparste JSON (BodyAsJSON), plus twee response-helpers: RespondJSON(code, content) voor een normale payload en RespondError(code, title, detail), die een application/problem+json-body in RFC 7807-stijl produceert zodat clients altijd een consistente foutvorm krijgen.
Code-first: de spec genereren uit Delphi-attributen
De tweede modus is de omgekeerde flow: u declareert uw API als een Delphi-klasse die met attributen is voorzien, vraagt de scanner om het OpenAPI-document tijdens runtime te genereren, en voert dat document terug in dezelfde component. Er is niets met de hand in JSON te schrijven.
uses
sgcHTTP_OpenAPI_Server_CodeFirst;
type
[sgcServiceContract('Task Manager API',
'A simple task manager', '1.0.0')]
[sgcRoute('/api/v1')]
TTaskService = class
public
[sgcHttpGet]
[sgcRoute('/tasks')]
[sgcSummary('List all tasks')]
[sgcResponse(200, 'A list of tasks')]
procedure ListTasks([sgcFromQuery] const status: string); virtual;
[sgcHttpGet]
[sgcRoute('/tasks/{taskId}')]
[sgcSummary('Get a task by ID')]
[sgcResponse(200, 'The requested task')]
[sgcResponse(404, 'Task not found')]
procedure GetTask([sgcFromPath][sgcRequired]
const taskId: Integer); virtual;
[sgcHttpPost]
[sgcRoute('/tasks')]
[sgcSummary('Create a new task')]
[sgcResponse(201, 'Task created')]
procedure CreateTask([sgcFromBody] const body: string); virtual;
end;
De klasse zelf hoeft geen echte bodies te hebben — de scanner leest haar via RTTI uit, de eigenlijke logica blijft in uw OnRequest-handler. De spec genereren en de server starten kost enkele regels:
var
oScanner: TsgcOpenAPICodeFirstScanner;
vSpec: string;
begin
oScanner := TsgcOpenAPICodeFirstScanner.Create;
try
vSpec := oScanner.GenerateSpec(TTaskService);
finally
oScanner.Free;
end;
FOpenAPI.LoadFromString(vSpec);
FOpenAPI.Server := WSServer;
WSServer.Active := True;
end;
De attributenset dekt de meest voorkomende gevallen: routing (sgcHttpGet, sgcHttpPost, sgcHttpPut, sgcHttpDelete, sgcHttpPatch, sgcRoute), parameterbinding (sgcFromPath, sgcFromQuery, sgcFromHeader, sgcFromBody), validatie (sgcRequired, sgcMinLength, sgcMaxLength, sgcRange, sgcPattern) en documentatie (sgcSummary, sgcDescription, sgcTag, sgcResponse).
Configuratie in detail
OpenAPIOptions is opgedeeld in drie persistente sub-objecten zodat u ze allemaal in de Object Inspector kunt zien:
Endpoint—BasePathplakt een prefix voor elke route en voor de ingebouwde/openapi.json- en/docs-endpoints;SpecFilekan tijdens ontwerptijd worden gebruikt als alternatief voorLoadFromFile;ServeSpecenServeSwaggerUIschakelen de twee ingebouwde endpoints in of uit (beide standaard aan).Validation— de hoofdschakelaar isValidateRequest; metValidateRequired,ValidateQueryParams,ValidatePathParamsenValidateRequestBodykunt u beperken wat er gecontroleerd wordt. Wanneer de validatie faalt, vuurtOnValidationErroraf met de lijst problemen en eenContinue-vlag — zet die opFalseom het verzoek automatisch te weigeren.CORS— zetEnabled := Trueen de server beantwoordt preflightOPTIONS-verzoeken op elke route, metAllowOrigins,AllowHeadersenAllowMethodsals responsebeleid.
Naast OnRequest bieden vier extra events u toegang tot de pijplijn: OnBeforeRequest (zet Accept := False om kortsluiting te maken, handig voor rate-limiting of logging), OnAfterRequest (nabewerking nadat u een respons hebt geproduceerd), OnAuthenticate (zet Authenticated := True nadat u een token of sessie hebt gecontroleerd) en OnException (vangnet waarmee u de HTTP-status kunt wijzigen voordat het framework de foutbody schrijft).
Swagger UI out of the box
Met ServeSwaggerUI := True publiceert de server een Swagger UI-pagina op BasePath + '/docs' die de spec laadt van BasePath + '/openapi.json'. Open de URL in een browser en u krijgt de bekende try-it-out-ervaring, gevoed door uw eigen draaiende server — geen aparte documentatiebuild, geen statische export. Gecombineerd met CORS is dit de snelste manier om een backend over te dragen aan een frontendteam of aan een partner die tegen uw API integreert.
Hoe u het krijgt
De component maakt deel uit van de Enterprise-editie van sgcWebSockets en is geregistreerd op de palette-pagina SGC OpenAPI. Twee complete demo's — één spec-first met een Petstore JSON, één code-first met een task manager-service — worden meegeleverd in Demos\23.OpenAPI. Download de meest recente build vanaf de sgcWebSockets downloadpagina.
Vragen, feedback of hulp nodig bij het inpassen in een bestaand project? Neem contact op — u krijgt antwoord van de mensen die de code geschreven hebben.
