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

· Wydania

Kolejne wydanie sgcOpenAPI — wersja 2026.6, planowane na czerwiec — dostarcza zupełnie nowy komponent: TsgcHTTPServer_OpenAPI. To pojedynczy, samodzielny komponent Delphi, który hostuje usługę OpenAPI 3.0 z wbudowanym serwerem HTTP. Upuść go na formularzu, wskaż specyfikację (lub wygeneruj ją z klasy Delphi za pomocą atrybutów RTTI), ustaw Active := True, 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. Nowy komponent jest dostarczany, pakowany i instalowany w całości z sgcOpenAPI. Jeśli już korzystasz z sgcWebSockets, dotychczasowy komponent TsgcWSServer_API_OpenAPI nadal działa bez zmian — oba wewnętrznie współdzielą ten sam silnik.

Co otrzymujesz w jednym komponencie

TsgcHTTPServer_OpenAPI łączy trzy elementy:

Szybki start — minimalny przykład

To wszystko, czego potrzebujesz, aby uruchomić działający serwer OpenAPI ze 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;

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 lub YAML (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.

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

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

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 znajduje się pod OpenAPIOptions, pogrupowana w trzy podopcje:

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

Komponent udostępnia sześć zdarzeń dla cyklu ż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.

Dema

Dwa kompletne dema są dostarczane z sgcOpenAPI 2026.6, oba używające wyłącznie nowego, samodzielnego komponentu — bez konieczności instalacji sgcWebSockets:

Aktualizacja

Jeśli obecnie używasz TsgcWSServer_API_OpenAPI wraz z sgcWebSockets, nic się nie zmienia — klasa, właściwości i zdarzenia zostały zachowane, a implementacja deleguje teraz pracę do tego samego współdzielonego silnika, który napędza nowy samodzielny komponent. Możesz pozostawić swój istniejący kod bez zmian lub migrować po jednym formularzu na raz do TsgcHTTPServer_OpenAPI, aby porzucić zależność od sgcWebSockets.

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.