sgcOpenAPI 2026.6 — samodzielny serwer OpenAPI, Spec-First lub Code-First

· Wydania
sgcOpenAPI 2026.6 — samodzielny serwer OpenAPI, Spec-First lub Code-First | Blog eSeGeCe

Kolejne wydanie sgcOpenAPI, wersja 2026.6, planowane na czerwiec, dostarcza serwer OpenAPI 3.0, który możesz hostować bez instalowania sgcWebSockets. Realizują to dwa komponenty: TsgcHTTPServer, serwer HTTP oparty na Indy, oraz TsgcWSAPIServer_OpenAPI, komponent API, który do niego podłączasz. Wskaż komponentowi API specyfikację (lub wygeneruj ją z klasy Delphi za pomocą atrybutów RTTI), przypisz jego właściwość Server, uruchom serwer HTTP, a otrzymasz udokumentowany REST API z automatycznie serwowanym Swagger UI.

Najważniejszą zmianą jest to, że sgcOpenAPI nie potrzebuje już sgcWebSockets do hostowania serwera HTTP. Oba komponenty są dostarczane, pakowane i instalowane w całości z sgcOpenAPI. Jeśli już korzystasz z sgcWebSockets, znany ci komponent TsgcWSServer_API_OpenAPI nadal działa bez zmian, ponieważ jest to ta sama klasa: oba produkty budują go z tego samego silnika.

Co otrzymujesz

Ta para zapewnia trzy elementy:

Szybki start — minimalny przykład

To wszystko, czego potrzebujesz, aby uruchomić działający serwer OpenAPI ze Swagger UI. Zauważ, że komponent API nie ma własnej właściwości Active: przypisanie Server podłącza go, a przypisanie nil odłącza, podczas gdy serwer HTTP nadal działa.

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;

Przejdź do http://localhost:8080/docs, aby zobaczyć Swagger UI, oraz do http://localhost:8080/openapi.json, aby zobaczyć specyfikację. Każda operacja zdefiniowana w specyfikacji jest kierowana do twojej procedury obsługi MyOnRequest wraz z rozwiązanym operationId oraz w pełni zbudowanym kontekstem żądania.

Spec-First — wczytaj istniejący plik OpenAPI 3.0

Jeśli masz już plik OpenAPI 3.0 w formacie JSON (Petstore, wewnętrzny kontrakt API, publiczny schemat, który chcesz zasymulować), podejście spec-first jest najszybszym sposobem na jego udostępnienie. LoadFromFile wczytuje i parsuje specyfikację, buduje tablicę tras na podstawie sekcji paths i dopasowuje do niej każde przychodzące żądanie. Serwer czyta JSON, więc najpierw przekonwertuj kontrakt YAML, na przykład za pomocą sgcOpenAPI.exe.

Kluczem do dyspozytora jest operationId każdej trasy. Wewnątrz OnRequest obsługujesz po kolei każdą operację:

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;

TsgcOpenAPIServerContext udostępnia typowane akcesory do wszystkiego w żądaniu: PathParamAsString / PathParamAsInteger dla szablonowych segmentów, QueryParamAsString / QueryParamAsInteger / QueryParamAsBoolean z wartościami domyślnymi, BodyAsString / BodyAsJSON dla treści żądania oraz HeaderValue dla dowolnego przychodzącego nagłówka. Aby odpowiedzieć, użyj pomocników RespondJSON(code, content) i RespondError(code, title, detail), lub ustaw Response.Code, Response.ContentType i Response.Content bezpośrednio, aby uzyskać pełną kontrolę.

Code-First — wygeneruj specyfikację z klasy Delphi

Jeśli wolisz napisać kontrakt API w Delphi i pozwolić, aby specyfikacja została wygenerowana, udekoruj klasę atrybutami RTTI. TsgcOpenAPICodeFirstScanner przechodzi przez klasę, buduje kompletny dokument JSON OpenAPI 3.0, a Ty wczytujesz go do serwera za pomocą LoadFromString. Wymaga to Delphi XE7 lub nowszego (dla rozszerzonego RTTI).

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;

Treści metod są zaślepkami — istnieją tylko po to, aby kompilator wyemitował dla nich RTTI. Właściwa praca odbywa się w OnRequest, dyspozycjonowana przez operationId, który skaner wyprowadza z każdej nazwy metody (ListTasks, CreateTask, GetTask…).

Przekaż klasę do skanera podczas uruchamiania i wczytaj wygenerowaną specyfikację do serwera:

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;

Atrybuty obejmują typowe metadane: sgcServiceContract wypełnia blok info w OpenAPI, sgcRoute ustawia ścieżkę na poziomie klasy lub metody, sgcHttpGet / Post / Put / Delete / Patch / Head / Options wybiera czasownik HTTP, sgcSummary i sgcDescription dokumentują operację, sgcTag grupuje ją w Swagger UI, sgcResponse(code, description) deklaruje każdą odpowiedź, a sgcFromPath / FromQuery / FromBody / FromHeader razem z sgcRequired opisują każdy parametr.

Konfiguracja — OpenAPIOptions

Cała konfiguracja po stronie serwera na komponencie API znajduje się pod OpenAPIOptions, pogrupowana w pięć podopcji. Te trzy zawierają ustawienia używane na co dzień:

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;

Przy włączonej walidacji każde przychodzące żądanie jest sprawdzane względem schematów JSON Schema zadeklarowanych w specyfikacji, zanim dotrze do twojej procedury obsługi — wymagane pola, typy, formaty, wyliczenia, zakresy. Niepowodzenia wywołują zdarzenie OnValidationError z listą błędów oraz flagą do akceptacji lub odrzucenia żądania.

Zdarzenia

Sześć zdarzeń obsługuje cykl życia żądania:

OnBeforeRequest: wywoływane przed dyspozytorem; ustaw Accept := False, aby odrzucić z kodem 403 Forbidden. Przydatne dla limitowania częstotliwości, logowania lub bramek na poziomie trasy.

OnAuthenticate: wywoływane przed główną procedurą obsługi; ustaw Authenticated := False, aby odrzucić z kodem 401 Unauthorized. Sprawdź nagłówki, cookies lub parametry zapytania, aby podjąć decyzję.

OnValidationError: wywoływane, gdy walidacja się nie powiedzie; odbiera listę błędów. Ustaw Continue := False, aby odrzucić z kodem 400 Bad Request.

OnRequest: główne zdarzenie dyspozytora. Spójrz na aOperationId, zapisz odpowiedź do aContext.Response, ustaw Handled := True.

OnAfterRequest: wywoływane po zakończeniu procedury obsługi — idealne dla metryk lub logowania audytu.

OnException: wywoływane, jeśli z procedury obsługi wycieknie nieobsłużony wyjątek. Dostosuj aResponseCode, jeśli chcesz coś innego niż 500 Internal Server Error.

Pozostałe dwa podopcje dodają własne funkcje: Security obsługuje OnValidateAPIKey, OnValidateBasic i OnValidateBearer dla securitySchemes zadeklarowanych w specyfikacji, a Mock odpowiada na operację bez procedury obsługi na podstawie przykładów z samej specyfikacji.

Dema

Dwa kompletne dema są dostarczane z sgcOpenAPI 2026.6, oba hostowane przez tę samodzielną parę, więc instalacja sgcWebSockets nie jest wymagana:

Aktualizacja

Jeśli obecnie używasz TsgcWSServer_API_OpenAPI wraz z sgcWebSockets, nic się nie zmienia. Klasa, jej właściwości i zdarzenia są w pełni zachowane, a implementacja deleguje pracę do tego samego współdzielonego silnika. TsgcWSAPIServer_OpenAPI jest publikowanym potomkiem tej samej klasy, więc jedyne, co zmienia sgcOpenAPI, to skąd pochodzi pakiet.

sgcOpenAPI 2026.6 będzie dostępne na stronie pobierania w czerwcu.

Masz pytania, opinie lub potrzebujesz pomocy z migracją? Skontaktuj się z nami — otrzymasz odpowiedź od osób, które napisały kod.