Edycja sgcWebSockets Enterprise dostarcza nowy komponent, TsgcWSAPIServer_OpenAPI, który zamienia opis OpenAPI 3 w działający serwer REST wewnątrz Twojej aplikacji Delphi. Upuść go na formularzu, wskaż serwer HTTP, przekaż specyfikację — a trasy, walidacja żądań, odpowiedzi błędów i dokumentacja na żywo w Swagger UI zostaną podłączone za Ciebie. Ten wpis przeprowadza przez to, jak działa komponent, dwa sposoby jego sterowania (spec-first i code-first), istotne pokrętła konfiguracyjne oraz kompletny przykład w Delphi, który możesz wkleić bezpośrednio do nowego projektu.
Co robi komponent
TsgcWSAPIServer_OpenAPI to lekki serwer API, który włącza się do TsgcWebSocketHTTPServer przez istniejący punkt rozszerzenia dla serwerów API. Podpinasz go do serwera, ładujesz specyfikację OpenAPI 3.0, a on dla każdego przychodzącego żądania HTTP wykonuje cztery rzeczy:
- dopasowuje URL i metodę HTTP do tras zadeklarowanych w specyfikacji (w tym parametrów
{path}); - waliduje żądanie — pola wymagane, parametry zapytania, parametry ścieżki i ciało żądania — względem schematów ze specyfikacji;
- wywołuje zdarzenie
OnRequestz rozpoznanymoperationIdi w pełni wypełnionym obiektem kontekstu, dzięki czemu Twój kod musi napisać tylko logikę biznesową; - od razu udostępnia dwa wbudowane punkty końcowe — surową specyfikację pod
/openapi.jsoni interaktywne Swagger UI pod/docs— z opcjonalnym preflight CORS na każdej trasie.
Efekt jest taki, że specyfikacja staje się jedynym źródłem prawdy: zmień ścieżkę, parametr lub kod odpowiedzi w JSON-ie, uruchom ponownie i serwer podejmuje nowy kontrakt bez rekompilacji kodu Delphi.
Spec-first: załaduj istniejący plik OpenAPI 3
Jeśli masz już dokument OpenAPI 3 (na przykład petstore.json wyeksportowany z projektanta API), podłączenie sprowadza się w istocie do trzech linii — utwórz komponent, załaduj specyfikację, podłącz serwer. Cała reszta to konfiguracja i obsługa zdarzenia OnRequest, która produkuje faktyczne odpowiedzi.
uses
sgcWebSocket, sgcWebSocket_Classes,
sgcWebSocket_Server_API_OpenAPI,
sgcHTTP_OpenAPI_Server;
var
WSServer: TsgcWebSocketHTTPServer;
FOpenAPI: TsgcWSAPIServer_OpenAPI;
begin
WSServer := TsgcWebSocketHTTPServer.Create(nil);
WSServer.Port := 8080;
FOpenAPI := TsgcWSAPIServer_OpenAPI.Create(nil);
FOpenAPI.OnRequest := OnOpenAPIRequest;
FOpenAPI.OnBeforeRequest := OnOpenAPIBeforeRequest;
FOpenAPI.OnValidationError := OnOpenAPIValidationError;
// Configuration
FOpenAPI.OpenAPIOptions.Endpoint.ServeSpec := True;
FOpenAPI.OpenAPIOptions.Endpoint.ServeSwaggerUI := True;
FOpenAPI.OpenAPIOptions.CORS.Enabled := True;
FOpenAPI.OpenAPIOptions.Validation.ValidateRequest := True;
FOpenAPI.OpenAPIOptions.Validation.ValidateRequired := True;
FOpenAPI.OpenAPIOptions.Validation.ValidateRequestBody := True;
// Load spec and attach to server
FOpenAPI.LoadFromFile('petstore.json');
FOpenAPI.Server := WSServer;
WSServer.Active := True;
// Swagger UI: http://localhost:8080/docs
// Raw spec: http://localhost:8080/openapi.json
end;
Zdarzenie OnRequest jest dystrybuowane per operationId, ciąg, który zapisałeś obok każdej operacji w dokumencie. Piszesz jedną gałąź na operację, czytasz wejścia z kontekstu i emitujesz odpowiedź:
procedure TForm1.OnOpenAPIRequest(Sender: TObject;
const aOperationId: string; const aContext: TsgcOpenAPIServerContext;
var Handled: Boolean);
var
vId: Int64;
vLimit: Integer;
begin
Handled := True;
if aOperationId = 'listPets' then
begin
vLimit := aContext.QueryParamAsInteger('limit', 100);
aContext.RespondJSON(200, BuildPetsJSON(vLimit));
end
else if aOperationId = 'getPetById' then
begin
vId := aContext.PathParamAsInteger('petId');
if FindPet(vId) then
aContext.RespondJSON(200, PetAsJSON(vId))
else
aContext.RespondError(404, 'Not Found',
Format('Pet %d not found', [vId]));
end
else
Handled := False;
end;
Obiekt TsgcOpenAPIServerContext jest koniem roboczym każdego handlera. Udostępnia parametry ścieżki i zapytania po nazwie (PathParamAsString, PathParamAsInteger, QueryParamAsString, QueryParamAsInteger, QueryParamAsBoolean), odczyt nagłówków przez HeaderValue, ciało jako tekst (BodyAsString) lub wstępnie sparsowany JSON (BodyAsJSON), a także dwa pomocnicze metody odpowiedzi: RespondJSON(code, content) dla zwykłego ładunku oraz RespondError(code, title, detail), który zapisuje ciało w formacie RFC 7807 z polami type, title, status i detail, dzięki czemu klienci zawsze otrzymują spójny kształt błędu.
Code-first: generuj specyfikację z atrybutów Delphi
Drugi tryb to przepływ odwrotny: deklarujesz swoje API jako klasę Delphi udekorowaną atrybutami, prosisz skaner o wyemitowanie dokumentu OpenAPI w czasie uruchomienia i przekazujesz ten dokument z powrotem do tego samego komponentu. Nie ma nic do napisania ręcznie w JSON.
uses
sgcHTTP_OpenAPI_Server_CodeFirst;
type
[sgcServiceContract('Task Manager API',
'A simple task manager', '1.0.0')]
[sgcRoute('/api/v1')]
TTaskService = class
public
[sgcHttpGet]
[sgcRoute('/tasks')]
[sgcSummary('List all tasks')]
[sgcResponse(200, 'A list of tasks')]
procedure ListTasks([sgcFromQuery] const status: string); virtual;
[sgcHttpGet]
[sgcRoute('/tasks/{taskId}')]
[sgcSummary('Get a task by ID')]
[sgcResponse(200, 'The requested task')]
[sgcResponse(404, 'Task not found')]
procedure GetTask([sgcFromPath][sgcRequired]
const taskId: Integer); virtual;
[sgcHttpPost]
[sgcRoute('/tasks')]
[sgcSummary('Create a new task')]
[sgcResponse(201, 'Task created')]
procedure CreateTask([sgcFromBody] const body: string); virtual;
end;
Sama klasa nie musi mieć rzeczywistych ciał metod — skaner czyta ją przez RTTI, a właściwa logika nadal żyje w Twoim handlerze OnRequest. Wygenerowanie specyfikacji i uruchomienie serwera to kilka linii:
var
oScanner: TsgcOpenAPICodeFirstScanner;
vSpec: string;
begin
oScanner := TsgcOpenAPICodeFirstScanner.Create;
try
vSpec := oScanner.GenerateSpec(TTaskService);
finally
oScanner.Free;
end;
FOpenAPI.LoadFromString(vSpec);
FOpenAPI.Server := WSServer;
WSServer.Active := True;
end;
Zestaw atrybutów pokrywa typowe przypadki: routing (sgcHttpGet, sgcHttpPost, sgcHttpPut, sgcHttpDelete, sgcHttpPatch, sgcRoute), wiązanie parametrów (sgcFromPath, sgcFromQuery, sgcFromHeader, sgcFromBody), walidację (sgcRequired, sgcMinLength, sgcMaxLength, sgcRange, sgcPattern) oraz dokumentację (sgcSummary, sgcDescription, sgcTag, sgcResponse).
Konfiguracja w szczegółach
OpenAPIOptions jest pogrupowany w pięć trwałych pod-obiektów, dzięki czemu możesz zobaczyć je wszystkie w Inspektorze Obiektów. Trzy z nich zawierają ustawienia używane na co dzień:
Endpoint—BasePathdodaje prefiks do każdej trasy oraz do wbudowanych punktów końcowych/openapi.jsoni/docs;SpecFilemoże być używany w czasie projektowania jako alternatywa dlaLoadFromFile;ServeSpeciServeSwaggerUIprzełączają dwa wbudowane punkty końcowe (oba domyślnie włączone).Validation— głównym przełącznikiem jestValidateRequest;ValidateRequired,ValidateQueryParams,ValidatePathParamsiValidateRequestBodypozwalają zawęzić to, co jest sprawdzane. Gdy walidacja się nie powiedzie, wywoływane jestOnValidationErrorz listą problemów i flagąContinue— ustaw ją naFalse, aby automatycznie odrzucić żądanie.CORS— ustawEnabled := True, a serwer odpowiada na preflightowe żądaniaOPTIONSdla każdej trasy, używającAllowOrigins,AllowHeadersiAllowMethodsjako polityki odpowiedzi.
Poza OnRequest kolejne zdarzenia pozwalają wpiąć się w potok: OnBeforeRequest (ustaw Accept := False, aby przerwać obsługę odpowiedzią 403 Forbidden, przydatne do ograniczania szybkości lub logowania), OnAfterRequest (post-przetwarzanie po wyprodukowaniu odpowiedzi), OnAuthenticate (wyczyść Authenticated, aby odpowiedzieć 401 Unauthorized po sprawdzeniu tokenu lub sesji) oraz OnException (uniwersalny przechwytujący wszystko, który pozwala zmienić status HTTP zanim framework zapisze ciało błędu). Pozostałe dwa pod-obiekty, Security i Mock, dodają OnValidateAPIKey, OnValidateBasic i OnValidateBearer dla schematów zadeklarowanych w specyfikacji oraz sztuczną odpowiedź dla operacji, dla której nikt jeszcze nie napisał kodu.
Swagger UI od razu po wyjęciu z pudełka
Przy ServeSwaggerUI := True serwer publikuje stronę Swagger UI pod BasePath + '/docs', która ładuje specyfikację z BasePath + '/openapi.json'. Otwórz URL w przeglądarce i otrzymasz standardowe doświadczenie try-it-out, zasilane z Twojego własnego działającego serwera — bez osobnego budowania dokumentacji, bez statycznego eksportu. W połączeniu z CORS jest to najszybszy sposób na przekazanie backendu zespołowi frontendowemu lub partnerowi integrującemu się z Twoim API.
Jak go zdobyć
Komponent jest częścią edycji Enterprise sgcWebSockets, zarejestrowanym na stronie palety SGC OpenAPI. Dwa kompletne dema — jedno spec-first wykorzystujące JSON Petstore, jedno code-first wykorzystujące usługę menedżera zadań — są dostarczane w Demos\23.OpenAPI. Pobierz najnowszą kompilację ze strony pobierania sgcWebSockets.
Pytania, opinie lub pomoc w podłączeniu komponentu do istniejącego projektu? Skontaktuj się z nami — otrzymasz odpowiedź od osób, które napisały kod.
