sgcOpenAPI 2026.9.0 to największe wydanie, jakie ten produkt kiedykolwiek miał. Poprzednia wersja radziła sobie z takim kształtem specyfikacji, jaki pokazuje większość samouczków, a przy wszystkim pozostałym po cichu traciła jakość. Tym razem parser został przejrzany funkcja po funkcji, względem specyfikacji OpenAPI 3.0, 3.1 i 3.2 oraz względem prawdziwych, opublikowanych dokumentów, a wynikiem jest 9 nowych funkcji, 26 poprawionych błędów i 5 celowych zmian łamiących zgodność.
W skrócie: wygenerowany klient jest teraz poprawny dla specyfikacji, które wcześniej dawały kod, który się nie kompilował, albo, co gorsza, kod, który się kompilował i wywoływał niewłaściwy adres URL.
Parser mówi teraz, czego nie potrafił zrobić
Stary parser miał jeden sposób zgłaszania kłopotów, czyli zgłoszenie wyjątku, i jeden sposób radzenia sobie z całą resztą, czyli ciche kontynuowanie pracy. Operacji, której nie potrafił wygenerować, po prostu nie było w wyniku, a dowiadywałeś się o tym, gdy zacząłeś szukać metody, której tam nie ma.
Każdy dokument wraca teraz z listą Warnings. Brakujący element openapi lub info, element o niewłaściwym typie JSON, operacja, której nie dało się wygenerować, nierozwiązane odwołanie do elementu ścieżki oraz słowo kluczowe JSON Schema, które jest odczytywane, ale jeszcze nieuwzględniane, wszystkie są tam zapisywane. Lista jest czyszczona przy każdym odczycie, więc to, co otrzymujesz, należy do dokumentu, który właśnie sparsowałeś.
uses
sgcOpenAPI_Classes, sgcOpenAPI_Parser_Client_Pascal;
var
oParser: TsgcOpenAPI_Parser_Client_Pascal;
i: Integer;
begin
oParser := TsgcOpenAPI_Parser_Client_Pascal.Create;
Try
oParser.OpenAPIClassName := 'TPetStoreClient';
oParser.OpenAPINamespace := 'PetStore';
oParser.OutputFileName := 'PetStoreClient.pas';
oParser.ReadFromFile('petstore.json');
for i := 0 to oParser.Warnings.Count - 1 do
Memo1.Lines.Add('warning: ' + oParser.Warnings[i]);
oParser.SaveToFile('PetStoreClient.pas');
Finally
oParser.Free;
End;
end;
Ustaw OutputFileName przed zapisem. Moduł Pascal kompiluje się tylko wtedy, gdy jego zadeklarowana nazwa odpowiada nazwie bazowej pliku, a generator nazywał moduł według dokumentu wejściowego, więc wygenerowanie MyClient.pas z petstore.json dawało moduł o nazwie petstore, który się nie kompilował. Teraz wygrywa nazwa pliku wyjściowego.
Wie, którą wersję czyta
OpenAPI 3.0 i 3.1 nie zgadzają się co do słów kluczowych, które mają tę samą nazwę, a stary parser traktował każdy dokument jak 3.0. Najwyraźniejszym przypadkiem jest exclusiveMinimum, który w 3.0 jest logicznym modyfikatorem słowa minimum, a w 3.1 samodzielną liczbą. Odczytanie jednego jako drugiego daje błędną granicę.
Wersja jest teraz parsowana do dialektu, udostępnianego jako Dialect, DialectMajor i DialectMinor, a każde słowo kluczowe, które się różni, jest odczytywane tak, jak wymaga tego jego własna wersja.
oParser.ReadFromFile('api.yaml');
case oParser.Dialect of
oapiDialect30: ShowMessage('OpenAPI 3.0');
oapiDialect31: ShowMessage('OpenAPI 3.1');
oapiDialect32: ShowMessage('OpenAPI 3.2');
end;
Do tego 3.1 wnosi webhooks, jsonSchemaDialect i components.pathItems, licencyjny identifier, schemat zabezpieczeń mutualTLS, typ zadeklarowany jako tablica, na przykład ["string","null"], oraz schemat zadeklarowany jako zwykła wartość logiczna. Wszystko to jest obsługiwane. Słowa kluczowe JSON Schema 2020-12, na które generator kodu jeszcze nie reaguje, są wczytywane do modelu i zgłaszane przez Warnings, więc luka jest widoczna zamiast niewidoczna.
Z 3.2 parser obsługuje operację query oraz mapę additionalOperations. Ścieżka deklarująca którąkolwiek z nich generuje teraz odpowiadające jej metody, wysyłane jako POST z nagłówkiem X-HTTP-Method-Override.
Parametry na poziomie ścieżki
To poprawka, którą odczuje najwięcej użytkowników. Specyfikacja pozwala zadeklarować parametr raz, na elemencie ścieżki, zamiast powtarzać go w każdej operacji poniżej, i to jest styl, który specyfikacja zaleca, i styl, którego używa większość publicznych dokumentów. Stary parser odczytywał te parametry, a potem je porzucał.
Wygenerowana metoda nie przyjmowała żadnych argumentów, a żądanie wychodziło z symbolem zastępczym wciąż obecnym w adresie URL, dosłownie /pets/{petId}. Wyglądało to na działającego klienta aż do chwili, gdy pierwsze wywołanie wróciło z kodem 404.
Schematy, które się składają
Składanie było najsłabszą częścią starego parsera, a każda jego odmiana była błędna na inny sposób. allOf zachowywał tylko ostatni z kilku schematów bazowych i odrzucał elementy pozostałych. oneOf scalał każdą gałąź w jedną klasę, co dawało zduplikowane pola. anyOf nie był obsługiwany w ogóle i sprowadzał się do łańcucha znaków. Schemat deklarujący jednocześnie properties i additionalProperties tracił wszystkie swoje właściwości.
Wszystkie cztery generują teraz to, co opisuje dokument. Schemat obiektu zadeklarowany w miejscu również otrzymuje własną klasę, zamiast degradować się do łańcucha znaków, a items jest odczytywany jako kompletny schemat, więc tablica obiektów zadeklarowanych w miejscu, tablica wyliczeń i tablica zagnieżdżona generują każda właściwy typ.
Wyliczenia, które niosą wartość oczekiwaną przez serwer
Wygenerowane tablice wyliczeń zawierały oczyszczony identyfikator Pascal zamiast wartości przesyłanej, więc allow-all wychodziło jako allowall, a json-file jako jsonfile. Każde żądanie zbudowane z takiego wyliczenia było odrzucane.
Tablice niosą teraz prawdziwą wartość, kolejność deklaracji ze specyfikacji jest zachowana, wyliczenia całkowite również dostają tablicę, a dodatkowo generowany jest element Unknown, dzięki czemu wartość dodana później przez serwer nie dekoduje się po cichu jako pierwszy element listy.
Nazwy właściwości są traktowane tak samo, tylko z drugiej strony. Właściwość schematu nazwana jak słowo zastrzeżone Delphi, na przykład property, class, string lub function, albo dwie właściwości różniące się tylko wielkością liter, na przykład Name i name, dawały moduł, który się nie kompilował. Właściwość otrzymuje teraz nową nazwę, a nazwa przesyłana jest zachowywana w atrybucie JSONName, więc serializacja nadal odpowiada dokumentowi.
Odpowiedzi, w tym te deklarowane tylko raz
Odpowiedź default oraz odpowiedzi zakresowe 2XX, 4XX i 5XX były po cichu porzucane. API, które deklaruje swoje błędy wyłącznie przez default, co jest częste, generowało klienta bez żadnego typowanego błędu. Teraz są odczytywane. Gdy zadeklarowano kilka odpowiedzi pomyślnych, używana jest ta o najniższym kodzie, a gdy operacja oferuje kilka typów nośnika, preferowany jest application/json.
Parametry w transmisji
Wygenerowany klient obsługuje teraz parametry cookie oraz komplet reguł serializacji parametrów OpenAPI: matrix, label, simple, form, spaceDelimited, pipeDelimited i deepObject, każdą z explode i allowReserved. Nowe metody AddArray i AddObject budują wartości strukturalne ręcznie, gdy zajdzie taka potrzeba.
// query parameters built with the serialization style the document declares
oRequest.AddArray('tags', ['dog', 'cat'], True); // explode
oRequest.AddObject('filter', ['color', 'red', 'size', 'M']);
Odwołania zewnętrzne
Specyfikacja podzielona na pliki ledwo działała. Odwołanie niosące fragment JSON Pointer, na przykład ./common.yaml#/components/schemas/Error, nie dawało się rozwiązać. Dwa pliki odwołujące się do siebie nawzajem wywracały parser. Odwołanie względne wewnątrz poddokumentu było rozwiązywane względem dokumentu głównego, a nie względem własnego pliku. Dwa pliki zewnętrzne o tej samej nazwie bazowej nadpisywały się nawzajem i mogły zastąpić schemat należący do dokumentu głównego. A łańcuch odwołań był śledzony dokładnie o jeden krok.
Wszystko to jest naprawione, a jedna rzecz została celowo zaostrzona: odwołanie zewnętrzne mogło wcześniej odczytać dowolny plik na maszynie, łącznie z ../../../credentials.json, i skopiować jego zawartość do wygenerowanego modułu. Odwołania zewnętrzne są teraz ograniczone do katalogu dokumentu głównego. Gdy układ plików naprawdę musi sięgnąć poza niego, ograniczenie znosi się jawnie.
uses
sgcOpenAPI_Bundle;
begin
// off by default: references may not leave the folder of the main document
sgcOpenAPIAllowRefsOutsideRoot := True;
end;
Pliki, które nie całkiem są w UTF-8
RFC 8259 mówi, że dokument JSON jest w UTF-8, a mnóstwo publikowanych specyfikacji takie nie jest. Plik ze znacznikiem kolejności bajtów był odrzucany z błędem UTF-8 w chwili, gdy zawierał jakikolwiek znak spoza ASCII, a tekst chiński lub japoński był po cichu zastępowany znakami zapytania.
Dokument, który nie jest poprawnym UTF-8, jest teraz odczytywany jako Windows-1252 z zapisanym ostrzeżeniem, zamiast kończyć się niepowodzeniem. Plik UTF-16 ze znacznikiem kolejności bajtów jest odczytywany poprawnie. Wygenerowany plik jest zapisywany z jawnym kodowaniem, a znak, którego kodowanie docelowe nie potrafi przedstawić, jest zgłaszany, zamiast po cichu stawać się znakiem zapytania.
Wiersz poleceń, który można umieścić w skrypcie budowania
Wiersz poleceń ustawia teraz kod wyjścia: 0 przy powodzeniu i od 1 do 7 dla poszczególnych niepowodzeń, dzięki czemu krok budowania wie, czy generowanie się udało. Komunikaty o błędach zawsze trafiają na standardowe wyjście błędów, a przełącznik -l służy teraz wyłącznie do rejestrowania postępu.
sgcOpenAPI -i petstore.json -o PetStoreClient.pas -c TPetStoreClient
if errorlevel 1 (
echo OpenAPI generation failed with exit code %errorlevel%
exit /b %errorlevel%
)
Poszły z tym trzy błędy wiersza poleceń. Udokumentowany przełącznik -output zapisywał moduł do pliku o nazwie utput w bieżącym katalogu, a ponieważ komunikaty były tłumione, przebieg nadal wyglądał na udany. Nic się w ogóle nie działo, gdy narzędzie uruchomiono bez dołączonej konsoli, czyli dokładnie w przypadku zadania zaplanowanego lub agenta budowania, a istniejące przekierowanie wyjścia było odrzucane. Oraz -h wypisywało błąd licencji zamiast tekstu pomocy na maszynie, która nie była aktywowana, niepoprawna wartość dla -m lub -a była przyjmowana po cichu, a nieznany przełącznik był ignorowany.
Nowość w tym wydaniu, -r (lub -remote) konwertuje dokument YAML albo Swagger 2.0 przez publiczny konwerter pod adresem converter.swagger.io. Domyślnie jest wyłączony, ponieważ wysyła twój dokument do strony trzeciej, więc to coś, co włącza się świadomie.
Sama konwersja Swagger 2.0 była zepsuta na dwa sposoby warte wymienienia. Każda liczba stawała się łańcuchem znaków, więc liczbowa wartość domyślna dawała moduł, który się nie kompilował, a przekonwertowany dokument nie był poprawnym OpenAPI 3.0. A discriminator ze Swagger 2.0, który jest tam zwykłym łańcuchem znaków, przerywał całe parsowanie niepoprawną konwersją typu.
Zmiany łamiące zgodność
Pięć zmian wymaga od ciebie decyzji, a nie samej tylko aktualizacji.
Wygenerowani klienci weryfikują teraz certyfikat serwera. Wcześniej tego nie robili, co oznacza, że przyjmowali dowolny certyfikat, także taki przedstawiony przez człowieka pośrodku. Aby sięgnąć do punktu końcowego z certyfikatem samopodpisanym lub testowym, wyłącz to świadomie.
oClient.TLSOptions.VerifyCertificate := False; // test endpoints only
// certificates are trusted through the OpenSSL default paths, so a machine
// with no certificate store configured needs an explicit root
oClient.TLSOptions.RootCertFile := 'cacert.pem';
Treść żądania jest w UTF-8. Tak, jak wymaga RFC 8259. Klasa serializuje teraz pusty łańcuch znaków jako "field": "", zamiast go pomijać. Wartościami null steruje się osobno.
oClient.JSONIgnoreEmptyStrings := True; // previous output
oClient.JSONIgnoreNullValues := True; // default
Odpowiedź nie zwalnia już dostarczonego przez ciebie ResponseStream. Ustaw OwnsResponseStream na True, aby wrócić do starego zachowania. Zwolnienie klienta z wnętrza jego własnej procedury obsługi OnResponse, OnError lub OnCancel zgłasza teraz czytelny błąd, zamiast się zawieszać.
Wartość przełącznika wiersza poleceń musi być zapisana jako -name value albo -name:value. Forma doklejona, bez separatora, taka jak -x"GET /pets", nie jest już przyjmowana. To właśnie ta forma sprawiała, że -x pasowało do innych przełączników zaczynających się na x, takich jak -xml.
Parametr zadeklarowany jako tablica jest generowany jako tablica. Wcześniej był generowany jako łańcuch znaków, więc sygnatura wygenerowanej metody zmienia się dla tych operacji.
Cała reszta
Pozostałe poprawki są tego rodzaju, że zauważa się je dopiero wtedy, gdy zaczynają boleć. Element o nieoczekiwanym typie JSON, na przykład "properties": [], przerywał parsowanie niepoprawną konwersją typu, zamiast zostać pominięty. Schemat typu integer bez wartości domyślnej dostawał wartość domyślną 0, a wyliczenie z jedną wartością było traktowane jak stała, co całkowicie usuwało parametr z wygenerowanej metody. Dwukrotne odczytanie tego samego dokumentu duplikowało każdą ścieżkę, znacznik, serwer i schemat. Rozszerzenie specyfikacji, takie jak x-tagGroups, umieszczone pośród ścieżek było odczytywane tak, jakby było ścieżką. enum, required i tags były parsowane pomocnikiem tekstowym rozdzielającym po przecinkach, więc wartość zawierająca przecinek albo sekwencję ucieczki JSON była dzielona lub uszkadzana. Wymaganie zabezpieczeń wymieniające kilka schematów zachowywało tylko pierwszy, gubiąc warunek, że spełnione mają być wszystkie. info.contact i info.license nie były odczytywane w ogóle, z powodu testu, który nigdy nie mógł być prawdziwy. Adres URL serwera z kilkoma zmiennymi podstawiał niewłaściwą wartość i mógł zgłosić błąd indeksu listy. Pakowanie specyfikacji nadpisywało plik wejściowy bez kopii zapasowej i bez komunikatu oraz usuwało z dokumentu każdy apostrof typograficzny. A specyfikacja przechowywana pod ścieżką zawierającą spację, taką jak C:\My Specs\, nie potrafiła rozwiązać swoich odwołań zewnętrznych.
Jak je zdobyć
sgcOpenAPI 2026.9.0 jest już dostępne, z pełnym kodem źródłowym i rokiem aktualizacji. Obsługuje Delphi 7 aż po Delphi 13 Florence oraz odpowiadające im wersje C++ Builder.
Strona produktu · Pobierz wersję próbną · Changelog
Masz pytania lub uwagi? Skontaktuj się z nami, otrzymasz odpowiedź od osób, które napisały ten kod.
