La prossima versione di sgcOpenAPI — la 2026.6, prevista per giugno — introduce un componente del tutto nuovo: TsgcHTTPServer_OpenAPI. Si tratta di un unico componente Delphi autonomo che ospita un servizio OpenAPI 3.0 con un server HTTP integrato. Trascinalo su una form, puntalo a una specifica (o generala da una classe Delphi con attributi RTTI), imposta Active := True e avrai una REST API documentata con Swagger UI servita automaticamente.
La novità principale è che sgcOpenAPI non ha più bisogno di sgcWebSockets per ospitare un server HTTP. Il nuovo componente è distribuito, impacchettato e installato interamente da sgcOpenAPI. Se usi già sgcWebSockets, il precedente componente TsgcWSServer_API_OpenAPI continua a funzionare senza modifiche — entrambi condividono internamente lo stesso engine.
Cosa ottieni in un solo componente
TsgcHTTPServer_OpenAPI racchiude tre elementi:
- Un server HTTP integrato (basato su Indy) con le consuete proprietà
Bindings,PorteActive. - L'engine OpenAPI: parsing della specifica, routing con path template e segmenti
{paramName}, validazione JSON-Schema, CORS, gestione delle eccezioni. - Due endpoint serviti automaticamente: la specifica su
/openapi.jsone una Swagger UI su/docs. Entrambi sono attivi di default e si possono abilitare o disabilitare inOpenAPIOptions.Endpoint.
Avvio rapido — l'esempio minimo
Questo è tutto ciò che serve per ospitare un server OpenAPI funzionante con Swagger UI:
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;
Vai su http://localhost:8080/docs per la Swagger UI e su http://localhost:8080/openapi.json per la specifica. Ogni operazione definita nella specifica viene instradata al tuo handler MyOnRequest con l'operationId risolto e un contesto della richiesta completamente costruito.
Spec-First — carica un file OpenAPI 3.0 esistente
Se hai già un file JSON o YAML OpenAPI 3.0 (Petstore, un contratto API interno, uno schema pubblico di cui vuoi fare il mock), spec-first è il modo più rapido per servirlo. LoadFromFile legge e analizza la specifica, costruisce una tabella di route dalla sezione paths e confronta ogni richiesta in arrivo con essa.
L'operationId di ciascuna route è la chiave di dispatch. All'interno di OnRequest gestisci una per una le operazioni:
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 ti fornisce accessor tipizzati per tutti gli elementi della richiesta: PathParamAsString / PathParamAsInteger per i segmenti template, QueryParamAsString / QueryParamAsInteger / QueryParamAsBoolean con valori di default, BodyAsString / BodyAsJSON per il corpo della richiesta e HeaderValue per qualsiasi header in arrivo. Per rispondere, usa gli helper RespondJSON(code, content) e RespondError(code, title, detail), oppure imposta direttamente Response.Code, Response.ContentType e Response.Content per il controllo completo.
Code-First — genera la specifica da una classe Delphi
Se preferisci scrivere il contratto API in Delphi e lasciare che la specifica venga generata, decora una classe con attributi RTTI. TsgcOpenAPICodeFirstScanner percorre la classe, costruisce un documento JSON OpenAPI 3.0 completo e tu lo carichi nel server con LoadFromString. Richiede Delphi XE7 o successivo (per l'RTTI estesa).
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;
I corpi dei metodi sono stub — esistono solo perché il compilatore emetta l'RTTI per essi. Il vero lavoro avviene in OnRequest, dove il dispatch usa l'operationId che lo scanner deriva dal nome di ciascun metodo (ListTasks, CreateTask, GetTask…).
Passa la classe allo scanner all'avvio e carica la specifica generata nel server:
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;
Gli attributi coprono i metadati comuni: sgcServiceContract popola il blocco info di OpenAPI, sgcRoute imposta il path a livello di classe o di metodo, sgcHttpGet / Post / Put / Delete / Patch / Head / Options sceglie il verbo, sgcSummary e sgcDescription documentano l'operazione, sgcTag la raggruppa nella Swagger UI, sgcResponse(code, description) dichiara ciascuna risposta e sgcFromPath / FromQuery / FromBody / FromHeader insieme a sgcRequired descrivono ciascun parametro.
Configurazione — OpenAPIOptions
Tutta la configurazione lato server risiede in OpenAPIOptions, raggruppata in tre sotto-opzioni:
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;
Con la validazione attiva, ogni richiesta in arrivo viene controllata rispetto ai JSON Schema dichiarati nella specifica prima di raggiungere il tuo handler — campi obbligatori, tipi, formati, enum, intervalli. In caso di errore viene scatenato l'evento OnValidationError con l'elenco degli errori e un flag per accettare o rifiutare la richiesta.
Eventi
Il componente espone sei eventi per il ciclo di vita della richiesta:
OnBeforeRequest: scatta prima del dispatch; imposta Accept := False per rifiutare con un 403 Forbidden. Utile per rate-limiting, logging o gate per singola route.
OnAuthenticate: scatta prima dell'handler principale; imposta Authenticated := False per rifiutare con 401 Unauthorized. Esamina header, cookie o parametri di query per decidere.
OnValidationError: scatta quando la validazione fallisce; riceve l'elenco degli errori. Imposta Continue := False per rifiutare con 400 Bad Request.
OnRequest: l'evento principale di dispatch. Guarda aOperationId, scrivi la risposta in aContext.Response, imposta Handled := True.
OnAfterRequest: scatta dopo che l'handler è ritornato — ideale per metriche o audit logging.
OnException: scatta se un'eccezione non gestita esce dal tuo handler. Modifica aResponseCode se vuoi qualcosa di diverso da 500 Internal Server Error.
Demo
Due demo complete sono incluse con sgcOpenAPI 2026.6, entrambe basate solo sul nuovo componente standalone — senza alcuna installazione di sgcWebSockets:
- Demos/30.Server/01.CodeFirst — una Task Manager API definita interamente con attributi su una classe Delphi.
- Demos/30.Server/02.SpecFirst — il classico esempio Petstore, servito da
petstore.json.
Aggiornamento
Se attualmente usi TsgcWSServer_API_OpenAPI con sgcWebSockets, non cambia nulla — la classe, le proprietà e gli eventi sono tutti preservati e l'implementazione ora delega allo stesso engine condiviso che alimenta il nuovo componente standalone. Puoi mantenere il codice esistente così com'è, oppure migrare una form alla volta a TsgcHTTPServer_OpenAPI per eliminare la dipendenza da sgcWebSockets.
sgcOpenAPI 2026.6 sarà disponibile sulla pagina dei download a giugno.
Domande, feedback o aiuto per la migrazione? Mettiti in contatto — riceverai una risposta dalle persone che hanno scritto il codice.
