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

· Versions
sgcOpenAPI 2026.6 — Serveur OpenAPI autonome, Spec-First ou Code-First | Blog eSeGeCe

La prochaine version de sgcOpenAPI, la version 2026.6, prévue pour juin, livre un serveur OpenAPI 3.0 que vous pouvez héberger sans installer sgcWebSockets. Deux composants s'en chargent : TsgcHTTPServer, le serveur HTTP basé sur Indy, et TsgcWSAPIServer_OpenAPI, le composant API que vous lui attachez. Pointez le composant API vers une spécification (ou générez-en une à partir d'une classe Delphi avec des attributs RTTI), affectez sa propriété Server, démarrez le serveur HTTP, 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. Les deux composants sont livrés, packagés et installés entièrement depuis sgcOpenAPI. Si vous utilisez déjà sgcWebSockets, le composant TsgcWSServer_API_OpenAPI que vous connaissez continue de fonctionner sans changement, car c'est la même classe : les deux produits la construisent à partir du même moteur.

Ce que vous obtenez

La paire apporte 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. Notez que le composant API n'a pas de propriété Active qui lui soit propre : c'est l'affectation de Server qui l'attache, et l'affectation de nil le détache pendant que le serveur HTTP continue de tourner.

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;

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 (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. Le serveur lit du JSON, convertissez donc d'abord un contrat YAML, par exemple avec sgcOpenAPI.exe.

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

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;

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_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;

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 sur le composant API, regroupée en cinq sous-options. Ces trois-ci portent les réglages courants :

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

Six événements couvrent 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.

Les deux sous-options restantes ajoutent les leurs : Security pilote OnValidateAPIKey, OnValidateBasic et OnValidateBearer pour les securitySchemes déclarés par la spécification, et Mock répond à une opération sans gestionnaire à partir des propres exemples de la spécification.

Démos

Deux démos complètes sont livrées avec sgcOpenAPI 2026.6, toutes deux hébergées par la paire autonome, de sorte qu'aucune installation de sgcWebSockets n'est requise :

Mise à niveau

Si vous utilisez actuellement TsgcWSServer_API_OpenAPI avec sgcWebSockets, rien ne change. La classe, ses propriétés et ses événements sont tous préservés, et l'implémentation délègue au moteur partagé. TsgcWSAPIServer_OpenAPI est le descendant publié de cette même classe, si bien que la seule chose que change sgcOpenAPI, c'est la provenance du package.

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.