sgcOpenAPI 2026.6 — Serveur OpenAPI autonome, Spec-First ou Code-First

· Versions

La prochaine version de sgcOpenAPI — la version 2026.6, prévue pour juin — livre un tout nouveau composant : TsgcHTTPServer_OpenAPI. Il s'agit d'un unique composant Delphi autonome qui héberge un service OpenAPI 3.0 avec un serveur HTTP embarqué. Posez-le sur une fiche, pointez-le vers une spécification (ou générez-en une à partir d'une classe Delphi avec des attributs RTTI), définissez Active := True, et vous obtenez une API REST documentée avec Swagger UI servi automatiquement.

Le changement principal est que sgcOpenAPI n'a plus besoin de sgcWebSockets pour héberger un serveur HTTP. Le nouveau composant est livré, packagé et installé entièrement depuis sgcOpenAPI. Si vous utilisez déjà sgcWebSockets, l'ancien composant TsgcWSServer_API_OpenAPI continue de fonctionner sans changement — les deux partagent le même moteur en interne.

Ce que vous obtenez dans un seul composant

TsgcHTTPServer_OpenAPI regroupe trois éléments :

Démarrage rapide — l'exemple minimal

Voici tout ce dont vous avez besoin pour héberger un serveur OpenAPI fonctionnel avec 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;

Naviguez vers http://localhost:8080/docs pour le Swagger UI et http://localhost:8080/openapi.json pour la spécification. Chaque opération définie dans la spécification est routée vers votre gestionnaire MyOnRequest avec l'operationId résolu et un contexte de requête entièrement construit.

Spec-First — charger un fichier OpenAPI 3.0 existant

Si vous avez déjà un fichier OpenAPI 3.0 au format JSON ou YAML (Petstore, un contrat d'API interne, un schéma public que vous souhaitez simuler), la méthode spec-first est la plus rapide pour le servir. LoadFromFile lit et analyse la spécification, construit une table de routage à partir de la section paths, et fait correspondre chaque requête entrante à celle-ci.

L'operationId de chaque route est la clé de dispatch. À l'intérieur de OnRequest, vous traitez chaque opération tour à tour :

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;

Le TsgcOpenAPIServerContext vous donne des accesseurs typés pour tout ce qui se trouve dans la requête : PathParamAsString / PathParamAsInteger pour les segments à modèle, QueryParamAsString / QueryParamAsInteger / QueryParamAsBoolean avec des valeurs par défaut, BodyAsString / BodyAsJSON pour le corps de la requête, et HeaderValue pour tout en-tête entrant. Pour répondre, utilisez les helpers RespondJSON(code, content) et RespondError(code, title, detail), ou définissez directement Response.Code, Response.ContentType et Response.Content pour un contrôle complet.

Code-First — générer la spécification à partir d'une classe Delphi

Si vous préférez écrire le contrat d'API en Delphi et laisser la spécification être générée, décorez une classe avec des attributs RTTI. TsgcOpenAPICodeFirstScanner parcourt la classe, construit un document JSON OpenAPI 3.0 complet, et vous le chargez dans le serveur avec LoadFromString. Cela nécessite Delphi XE7 ou plus récent (pour le RTTI étendu).

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;

Les corps des méthodes sont des stubs — ils n'existent que pour que le compilateur émette le RTTI correspondant. Le vrai travail se fait dans OnRequest, dispatché par l'operationId que le scanner dérive de chaque nom de méthode (ListTasks, CreateTask, GetTask…).

Transmettez la classe au scanner au démarrage et chargez la spécification générée dans le serveur :

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;

Les attributs couvrent les métadonnées courantes : sgcServiceContract remplit le bloc info d'OpenAPI, sgcRoute définit le chemin au niveau de la classe ou de la méthode, sgcHttpGet / Post / Put / Delete / Patch / Head / Options choisit le verbe, sgcSummary et sgcDescription documentent l'opération, sgcTag la regroupe dans Swagger UI, sgcResponse(code, description) déclare chaque réponse, et sgcFromPath / FromQuery / FromBody / FromHeader avec sgcRequired décrivent chaque paramètre.

Configuration — OpenAPIOptions

Toute la configuration côté serveur se trouve sous OpenAPIOptions, regroupée en trois sous-options :

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;

Avec la validation activée, chaque requête entrante est vérifiée par rapport aux schémas JSON déclarés dans la spécification avant d'atteindre votre gestionnaire — champs obligatoires, types, formats, énumérations, plages de valeurs. Les échecs déclenchent l'événement OnValidationError avec la liste des erreurs et un indicateur pour accepter ou rejeter la requête.

Événements

Le composant expose six événements pour le cycle de vie de la requête :

OnBeforeRequest : se déclenche avant le dispatch ; définissez Accept := False pour rejeter avec un 403 Forbidden. Utile pour la limitation de débit, la journalisation ou les contrôles par route.

OnAuthenticate : se déclenche avant le gestionnaire principal ; définissez Authenticated := False pour rejeter avec 401 Unauthorized. Inspectez les en-têtes, les cookies ou les paramètres de requête pour décider.

OnValidationError : se déclenche lorsque la validation échoue ; reçoit la liste des erreurs. Définissez Continue := False pour rejeter avec 400 Bad Request.

OnRequest : l'événement principal de dispatch. Regardez aOperationId, écrivez la réponse dans aContext.Response, définissez Handled := True.

OnAfterRequest : se déclenche après le retour du gestionnaire — idéal pour les métriques ou la journalisation d'audit.

OnException : se déclenche si une exception non gérée remonte depuis votre gestionnaire. Ajustez aResponseCode si vous souhaitez autre chose que 500 Internal Server Error.

Démos

Deux démos complètes sont livrées avec sgcOpenAPI 2026.6, toutes deux utilisant uniquement le nouveau composant autonome — aucune installation de sgcWebSockets requise :

Mise à niveau

Si vous utilisez actuellement TsgcWSServer_API_OpenAPI avec sgcWebSockets, rien ne change — la classe, les propriétés et les événements sont tous préservés et l'implémentation délègue désormais au même moteur partagé qui alimente le nouveau composant autonome. Vous pouvez conserver votre code existant tel quel, ou migrer une fiche à la fois vers TsgcHTTPServer_OpenAPI pour supprimer la dépendance à sgcWebSockets.

sgcOpenAPI 2026.6 sera disponible sur la page de téléchargements en juin.

Questions, retours ou aide à la migration ? Contactez-nous — vous obtiendrez une réponse des personnes qui ont écrit le code.