OpenAPI | Serveur | Spec-First

Dans l'approche Spec-First, la spécification OpenAPI 3.0 (JSON ou YAML) est la source de vérité : elle décrit chaque chemin, opération, paramètre et schéma. Lorsque le serveur démarre, il analyse la spécification et construit la table de routage automatiquement ; vous n'avez qu'à fournir la logique métier pour chaque opération.

Ce workflow est celui recommandé lorsque le contrat de l'API existe déjà, lorsqu'il est partagé avec les consommateurs, ou lorsqu'il est maintenu en dehors du code Delphi.

Chargement de la spécification

Utilisez LoadFromFile pour charger la spécification depuis le disque, ou LoadFromString pour la charger depuis une chaîne en mémoire (par exemple, une spécification récupérée depuis une base de données ou générée à l'exécution).


uses sgcHTTPServer_OpenAPI;

var
  oServer: TsgcHTTPServer_OpenAPI;
begin
  oServer := TsgcHTTPServer_OpenAPI.Create(nil);
  oServer.Bindings.Add.Port := 8080;
  oServer.LoadFromFile('petstore.json');
  oServer.OnRequest := MyOnRequest;
  oServer.Active := True;
end;

Une fois chargée, la table de routage est construite à partir de la section paths de la spécification. Les segments de modèle tels que /pets/{petId} sont reconnus automatiquement et les valeurs capturées sont exposées via aContext.PathParamAsXxx.

Gestion des opérations

Le serveur dispatche chaque requête entrante à l'événement OnRequest, en passant l'operationId déclaré dans la spécification. Utilisez une simple chaîne if/else (ou une recherche dans un dictionnaire) pour router l'opération vers le bon gestionnaire.


procedure TForm1.MyOnRequest(Sender: TObject; const aOperationId: string;
  const aContext: TsgcOpenAPIServerContext; var Handled: Boolean);
begin
  if aOperationId = 'listPets' then
    DoListPets(aContext)
  else if aOperationId = 'getPetById' then
    DoGetPetById(aContext)
  else if aOperationId = 'createPet' then
    DoCreatePet(aContext)
  else
    aContext.RespondError(404, 'Not Found', 'Unknown operation');

  Handled := True;
end;

Lecture des données de requête

L'objet TsgcOpenAPIServerContext expose des accesseurs typés pour chaque partie de la requête :


procedure TForm1.DoGetPetById(const aContext: TsgcOpenAPIServerContext);
var
  vPetId: Integer;
  vFields: string;
  vBody: string;
begin
  // path parameter declared as /pets/{petId}
  vPetId := aContext.PathParamAsInteger('petId');

  // optional query string ?fields=name,status
  vFields := aContext.QueryParamAsString('fields', 'name');

  // raw request body (when present)
  vBody := aContext.BodyAsString;
end;

Écriture des réponses

L'objet contexte fournit également des utilitaires pour écrire la réponse. Les plus courants sont RespondJSON et RespondError ; pour un contrôle total sur la réponse, définissez directement aContext.Response.Code et aContext.Response.ContentText.


// success: 200 with JSON body
aContext.RespondJSON(200, '{"id":1,"name":"Rex"}');

// error: 404 with title and detail
aContext.RespondError(404, 'Not Found', 'Pet not found');

// full control
aContext.Response.Code := 201;
aContext.Response.ContentType := 'application/json';
aContext.Response.ContentText := '{"id":42}';

Validation

Lorsque les indicateurs de validation sous OpenAPIOptions.Validation sont activés, le serveur valide chaque requête par rapport aux JSON-Schemas déclarés dans la spécification avant d'invoquer OnRequest :

ValidateRequestBody : le corps de la requête est vérifié par rapport au schéma référencé par requestBody de l'opération.

ValidateQueryParams : les paramètres de la chaîne de requête sont vérifiés par rapport à leurs schémas déclarés.

ValidatePathParams : les paramètres de chemin sont vérifiés par rapport à leurs schémas déclarés.

ValidateRequired : la requête est rejetée lorsqu'un paramètre déclaré comme obligatoire est manquant.

Lorsque la validation échoue, l'événement OnValidationError se déclenche avec la liste des erreurs. Définissez Continue sur False pour rejeter la requête avec une réponse 400, ou laissez-le à True pour laisser votre gestionnaire OnRequest décider.


oServer.OpenAPIOptions.Validation.ValidateRequest := True;
oServer.OpenAPIOptions.Validation.ValidateRequestBody := True;
oServer.OpenAPIOptions.Validation.ValidateRequired := True;

Démo

Un exemple spec-first complet est fourni sous Demos/30.Server/02.SpecFirst/.