Dowiedz się, jak wygenerować OpenAPI na podstawie zachowania za pomocą Claude Code, porównać je z implementacją API i stworzyć proste przykłady walidacji klienta i serwera.

Kontrakt OpenAPI to wspólny opis twojego API: jakie istnieją endpointy, co wysyłasz, co otrzymujesz i jak wyglądają błędy. To porozumienie między serwerem a każdym, kto go wywołuje (aplikacją webową, mobilną lub inną usługą).
Problemem jest drift. Działające API się zmienia, a spec nie. Albo spec jest „wyczyszczony”, żeby wyglądać ładniej niż rzeczywistość, podczas gdy implementacja wciąż zwraca dziwne pola, brakujące status kody lub niespójne kształty błędów. Z czasem ludzie przestają ufać plikowi OpenAPI i staje się on kolejnym dokumentem, którego nikt nie czyta.
Drift zwykle wynika z naturalnych nacisków: szybka poprawka trafia do produkcji bez aktualizacji specu, dodaje się nowe pole opcjonalne „tymczasowo”, zmienia się paginacja albo zespoły aktualizują różne „źródła prawdy” (kod backendu, kolekcja Postman i plik OpenAPI).
Uczciwość oznacza, że spec odpowiada rzeczywistemu zachowaniu. Jeśli API czasem zwraca 409 dla konfliktu, powinno to być w kontrakcie. Jeśli pole jest nullable, zapisz to. Jeśli wymagana jest autoryzacja, nie zostawiaj tego niejasnym.
Dobry workflow daje ci:
Ten ostatni punkt ma znaczenie, ponieważ kontrakt pomaga tylko wtedy, gdy jest egzekwowany. Uczciwy spec plus powtarzalne sprawdzenia zamienia „dokumentację API” w coś, na czym zespoły mogą polegać.
Jeśli zaczniesz od czytania kodu lub kopiowania tras, twój OpenAPI będzie opisywał to, co jest dziś — łącznie z dziwactwami, których możesz nie chcieć obiecywać. Zamiast tego opisz, co API powinno robić dla wywołującego, a potem użyj specu, aby zweryfikować, że implementacja się zgadza.
Zanim napiszesz YAML lub JSON, zbierz mały zestaw faktów dla każdego endpointu:
Potem zapisz zachowanie jako przykłady. Przykłady zmuszają do precyzji i ułatwiają szkicowanie spójnego kontraktu.
Dla API z zadaniami (Tasks API) przykład happy pathu może brzmieć: „Utwórz zadanie z title i otrzymaj id, title, status i createdAt.” Dodaj typowe błędy: „Brak title zwraca 400 z {\"error\":\"title is required\"}” i „Brak auth zwraca 401.” Jeśli znasz edge case’y, uwzględnij je: czy duplikaty tytułów są dozwolone i co się dzieje, gdy ID zadania nie istnieje.
Zapisuj reguły jako proste zdania niezależne od szczegółów kodu:
title jest wymagane i ma 1–120 znaków.”limit (max 200).”dueDate to data-czas w formacie ISO 8601.”Na koniec zdecyduj o zakresie v1. Jeśli nie jesteś pewien, utrzymaj v1 małe i jasne (create, read, list, update status). Odłóż wyszukiwanie, operacje masowe i złożone filtry na później, żeby kontrakt pozostał wiarygodny.
Zanim poprosisz Claude Code o napisanie specu, zapisz notatki o zachowaniu w krótkim, powtarzalnym formacie. Celem jest utrudnienie „wypełniania luk” domysłami.
Dobry szablon jest na tyle krótki, żebyś go rzeczywiście używał, ale wystarczająco konsekwentny, żeby dwie osoby opisały ten sam endpoint podobnie. Skup się na tym, co API robi, a nie jak jest zaimplementowane.
Użyj jednego bloku na endpoint:
METHOD + PATH:
Purpose (1 sentence):
Auth:
Request:
- Query:
- Headers:
- Body example (JSON):
Responses:
- 200 OK example (JSON):
- 4xx example (status + JSON):
Edge cases:
Data types (human terms):
Napisz przynajmniej jedno konkretne żądanie i dwie odpowiedzi. Dołącz status kody i realistyczne JSON-y z prawdziwymi nazwami pól. Jeśli pole jest opcjonalne, pokaż przykład, w którym go brakuje.
Wypisz edge case’y wprost. To miejsca, gdzie specyfikacje cicho przestają być prawdziwe, bo każdy coś założył inaczej: puste wyniki, nieprawidłowe ID (400 vs 404), duplikaty (409 vs zachowanie idempotentne), błędy walidacji i limity paginacji.
Zanotuj też typy danych prostym językiem zanim pomyślisz o schematach: stringi vs liczby, formaty date-time, boole, enumy (lista dozwolonych wartości). To zapobiega „ładnym” schematom, które nie pasują do rzeczywistych payloadów.
Claude Code działa najlepiej, gdy traktujesz go jak uważnego skrybę. Podaj mu notatki o zachowaniu i ścisłe reguły dotyczące struktury OpenAPI. Jeśli powiesz tylko „napisz spec OpenAPI”, zwykle dostaniesz domysły, niespójne nazwy i brakujące przypadki błędów.
Wklej najpierw notatki o zachowaniu, potem dodaj krótki blok instrukcji. Praktyczny prompt wygląda tak:
You are generating an OpenAPI 3.1 YAML spec.
Source of truth: the behavior notes below. Do not invent endpoints or fields.
If anything is unclear, list it under ASSUMPTIONS and leave TODO markers in the spec.
Requirements:
- Include: info, servers (placeholder), tags, paths, components/schemas, components/securitySchemes.
- For each operation: operationId, tags, summary, description, parameters, requestBody (when needed), responses.
- Model errors consistently with a reusable Error schema and reference it in 4xx/5xx responses.
- Keep naming consistent: PascalCase schema names, lowerCamelCase fields, stable operationId pattern.
Behavior notes:
[PASTE YOUR NOTES HERE]
Output only the OpenAPI YAML, then a short ASSUMPTIONS list.
Po otrzymaniu szkicu najpierw przejrzyj ASSUMPTIONS. Tam wygrywa uczciwość lub się psuje. Zatwierdź to, co właściwe, popraw to, co nieprawidłowe, i uruchom ponownie z zaktualizowanymi notatkami.
Aby utrzymać konsekwencję nazw, zadeklaruj konwencje na początku i trzymaj się ich: na przykład stabilny wzorzec operationId, nazwy tagów jako rzeczowniki, pojedyncze nazwy schematów, jeden współdzielony Error i jedna nazwa schemy auth używana wszędzie.
Jeśli pracujesz w środowisku vibe-coding takim jak Koder.ai, warto zapisać YAML jako prawdziwy plik wcześnie i iterować w małych diffach. Widać wtedy, które zmiany pochodzą z zatwierdzonych decyzji o zachowaniu, a które z domysłów modelu.
Zanim porównasz cokolwiek z produkcją, upewnij się, że plik OpenAPI jest wewnętrznie spójny. To najszybsze miejsce, żeby złapać życzeniowe myślenie i niejasne zapisy.
Przeczytaj każdy endpoint jak deweloper klienta. Skup się na tym, co wywołujący musi wysłać i na co może liczyć zwracając.
Praktyczny przegląd:
Odpowiedzi błędów zasługują na szczególną uwagę. Wybierz jeden wspólny kształt i używaj go wszędzie. Nie mieszaj prostego { error: string } z bardziej złożonym obiektem, bo klienci będą dodawać specjalne przypadki.
Prosty scenariusz sanityzacyjny pomaga. Jeśli POST /tasks wymaga title, schema powinna to oznaczać jako required, odpowiedź błędu powinna pokazywać faktyczny kształt zwracanego błędu, a operacja jasno określać, czy auth jest wymagana.
Gdy spec czyta się jak zamierzone zachowanie, potraktuj działające API jako prawdę dotyczącą doświadczenia klienta dziś. Celem nie jest „wygrać” między spec a kodem, tylko wczesne uwidocznienie różnic i podjęcie jasnej decyzji w każdym przypadku.
Na pierwszy rzut oka próbki rzeczywistych request/response są zwykle najprostszą opcją. Logi i testy automatyczne też działają, jeśli są rzetelne.
Uważaj na typowe rozbieżności: endpointy obecne w jednym miejscu, a nieobecne w drugim, różnice w nazwach pól lub ich kształtach, różnice w status kodach (200 vs 201, 400 vs 422), nieudokumentowane zachowania (paginacja, sortowanie, filtrowanie) i różnice w auth (spec mówi publiczne, kod wymaga tokenu).
Przykład: spec mówi POST /tasks zwraca 201 z {id,title}. Wywołujesz działające API i dostajesz 200 plus {id,title,createdAt}. To nie jest „wystarczająco bliskie”, jeśli generujesz SDK z spec.
Zanim cokolwiek edytujesz, zdecyduj jak rozwiązać konflikt:
Trzymaj każdą zmianę małą i łatwą do przeglądu: jeden endpoint, jedna odpowiedź, jedna zmiana schematu. Łatwiej to sprawdzić i przetestować.
Gdy masz spec, któremu ufasz, zamień go na małe przykłady walidacji. To właśnie zatrzymuje drift, zanim wróci.
Na serwerze walidacja oznacza szybkie odrzucanie żądań, które nie pasują do kontraktu, i zwracanie jasnego błędu. To chroni dane i ułatwia wykrywanie błędów.
Prosty sposób na wyrażenie przykładów walidacji serwera to zapisanie przypadków z trzema częściami: input, oczekiwany output i oczekiwany błąd (kod błędu lub wzorzec komunikatu, nie dokładny tekst).
Przykład (kontrakt mówi, że title jest wymagane i ma 1–120 znaków):
{
\"name\": \"Create task without title returns 400\",
\"request\": {\"method\": \"POST\", \"path\": \"/tasks\", \"body\": {\"title\": \"\"}},
\"expect\": {\"status\": 400, \"body\": {\"error\": {\"code\": \"VALIDATION_ERROR\"}}}
}
Na kliencie walidacja polega na wykryciu dryfu zanim zrobią to użytkownicy. Jeśli serwer zacznie zwracać inny kształt, albo wymagane pole zniknie, testy powinny to zgłosić.
Skupiaj kontrole klienta na tym, na czym naprawdę polegasz, jak „task ma id, title, status.” Unikaj asercji wszystkich pól opcjonalnych lub dokładnego porządku. Chcesz, żeby testy łapały breaking changes, a nie nieszkodliwe dodatki.
Kilka zasad, które utrzymują testy czytelnymi:
Jeśli budujesz w Koder.ai, możesz trzymać te przykłady obok pliku OpenAPI i aktualizować je w tym samym przeglądzie zmian co spec.
Wyobraź sobie małe API z trzema endpointami: POST /tasks tworzy zadanie, GET /tasks listuje zadania, a GET /tasks/{id} zwraca jedno zadanie.
Zacznij od napisania kilku konkretnych przykładów dla jednego endpointu, jakbyś tłumaczył testerowi.
Dla POST /tasks zamierzone zachowanie może być:
{ \"title\": \"Buy milk\" } i otrzymaj 201 z nowym obiektem taska, zawierającym id, title i done:false.{} i otrzymaj 400 z błędem jak { \"error\": \"title is required\" }.{ \"title\": \"x\" } (za krótki) i otrzymaj 422 z { \"error\": \"title must be at least 3 characters\" }.Gdy Claude Code szkicuje OpenAPI, fragment dla tego endpointu powinien uchwycić schemat, status kody i realistyczne przykłady:
paths:
/tasks:
post:
summary: Create a task
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateTaskRequest'
examples:
ok:
value: { \"title\": \"Buy milk\" }
responses:
'201':
description: Created
content:
application/json:
schema:
$ref: '#/components/schemas/Task'
examples:
created:
value: { \"id\": \"t_123\", \"title\": \"Buy milk\", \"done\": false }
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
missingTitle:
value: { \"error\": \"title is required\" }
'422':
description: Unprocessable Entity
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
tooShort:
value: { \"error\": \"title must be at least 3 characters\" }
Częsta, subtelna rozbieżność to: działające API zwraca 200 zamiast 201, albo zwraca { \"taskId\": 123 } zamiast { \"id\": \"t_123\" }. To „prawie to samo” psuje generowane SDK.
Napraw to, wybierając jedno źródło prawdy. Jeśli zamierzone zachowanie jest poprawne, zmień implementację, żeby zwracała 201 i uzgodniony kształt Task. Jeśli produkcja jest już wykorzystywana, zaktualizuj spec (i notatki o zachowaniu), a potem dodaj brakujące walidacje i odpowiedzi błędów, żeby klienci nie byli zaskoczeni.
Kontrakt staje się nieuczciwy, gdy przestaje opisywać reguły, a zaczyna opisywać to, co twoje API zwróciło w jakiś dobry dzień. Prosty test: czy nowa implementacja mogłaby przejść ten spec nie kopiując dzisiejszych dziwactw?
Jedna pułapka to przeuczenie (overfitting). Złapiesz jedną odpowiedź i zrobisz z niej prawo. Przykład: twoje API teraz zawsze zwraca dueDate: null, więc spec mówi, że pole jest zawsze nullable. Ale prawdziwa reguła może brzmieć „wymagane, gdy status jest scheduled.” Kontrakt powinien wyrażać regułę, nie tylko dzisiejszy zestaw danych.
Błędy to miejsce, gdzie uczciwość najczęściej się psuje. Kuszące jest specyfikować tylko odpowiedzi sukcesu, bo wyglądają czysto. Klienci jednak potrzebują podstaw: 401 gdy tokenu brakuje, 403 dla braku uprawnień, 404 dla nieznanych ID i spójny kształt błędu walidacji (400 lub 422).
Inne wzorce, które powodują problemy:
taskId w jednym, a id w drugim; priority jako string vs number).string, wszystko opcjonalne).Dobry kontrakt jest testowalny. Jeśli nie możesz napisać z niego testu, który failuje, kontrakt wciąż nie jest uczciwy.
Zanim dasz plik innemu zespołowi, zrób szybki przegląd: „czy ktoś może użyć tego bez czytania twoich myśli?”
Zacznij od przykładów. Spec może być poprawna, a i tak bezużyteczna, jeśli każde żądanie i odpowiedź są abstrakcyjne. Dla każdej operacji dołącz przynajmniej jeden realistyczny request i jedną odpowiedź sukcesu. Dla błędów jeden przykład na powszechny błąd (auth, walidacja) zwykle wystarczy.
Potem sprawdź spójność. Jeśli jeden endpoint zwraca { \"error\": \"...\" }, a inny { \"message\": \"...\" }, klienci będą mieć rozgałęzienia wszędzie. Wybierz jeden kształt błędu i używaj go powtarzalnie, razem z przewidywalnymi status kodami.
Krótka lista kontrolna:
Praktyczny trik: wybierz jeden endpoint, udawaj, że nigdy nie widziałeś API i odpowiedz na pytanie „co wysyłam, co dostaję z powrotem i co się psuje?” Jeśli OpenAPI nie odpowie jasno, nie jest gotowe.
Ten workflow się zwraca, gdy działa regularnie, nie tylko podczas przygotowań do wydania. Wybierz prostą zasadę i trzymaj się jej: uruchamiaj proces przy każdej zmianie endpointu i znów przed opublikowaniem zaktualizowanego specu.
Uprość właścicielstwo. Osoba, która zmienia endpoint, aktualizuje notatki o zachowaniu i szkic specu. Druga osoba przegląda „spec vs implementation” jak code review. QA lub osoby ze wsparcia często świetnie sprawdzają się jako recenzenci, bo szybko wyłapują niejasne odpowiedzi i edge case’y.
Traktuj edycje kontraktu jak zmiany w kodzie. Jeśli używasz narzędzia chat-driven jak Koder.ai, zrób snapshot przed ryzykownymi zmianami i użyj rollbacku, jeśli trzeba. Koder.ai pozwala też eksportować kod źródłowy, co ułatwia trzymanie specu i implementacji obok siebie w repo.
Rutyna, która zwykle działa bez spowalniania zespołów:
Następne działanie: wybierz jeden endpoint, który już istnieje. Napisz 5–10 linii notatek o zachowaniu (wejścia, wyjścia, przypadki błędów), wygeneruj szkic OpenAPI z tych notatek, zweryfikuj go, porównaj z działającą implementacją. Napraw jedną rozbieżność, przetestuj i powtórz. Po jednym endpointzie nawyk zwykle się utrwala.
OpenAPI drift to sytuacja, gdy uruchamiane API nie zgadza się już z plikiem OpenAPI, który jest udostępniany. Specyfikacja może nie zawierać nowych pól, status kodów lub zasad autoryzacji, albo opisywać „idealne” zachowanie, którego serwer nie przestrzega.
To ma znaczenie, ponieważ klienci (aplikacje, inne usługi, generowane SDK, testy) podejmują decyzje na podstawie kontraktu, a nie tego, co serwer „zwykle” robi.
Drift objawia się jako trudne do zdiagnozowania awarie klienta: aplikacja mobilna spodziewa się 201, a dostaje 200, SDK nie potrafi zdeserializować odpowiedzi, bo pole zostało przemianowane, albo obsługa błędów zawodzi z powodu innego kształtu błędu.
Nawet jeśli nic nie pada, zespoły tracą zaufanie i przestają używać specyfikacji — przez to tracisz wczesny system ostrzegania o problemach.
Bo kod odzwierciedla aktualne zachowanie, łącznie z przypadkowymi niedoskonałościami, których może nie chcesz obiecywać na dłużej.
Lepszym domyśłem jest: najpierw opisz zamierzone zachowanie (wejścia, wyjścia, błędy), a potem zweryfikuj, czy implementacja się z tym zgadza. Dzięki temu masz kontrakt, który można egzekwować, a nie tylko zdjęcie dzisiejszych tras.
Dla każdego endpointu zanotuj:
Jeśli potrafisz napisać konkretną prośbę i dwie odpowiedzi, zwykle masz wystarczająco, żeby przygotować prawdziwą specyfikację.
Wybierz jedną formę odpowiedzi błędu i używaj jej wszędzie.
Prosty domyślny kształt to albo:
{ "error": "message" }, albo{ "error": { "code": "...", "message": "...", "details": ... } }Następnie konsekwentnie używaj tego kształtu w endpointach i przykładach. Spójność jest ważniejsza niż złożoność, bo klienci będą to twardo obsługiwać.
Podaj Claude Code swoje notatki o zachowaniu i ścisłe reguły, i powiedz mu, żeby niczego nie wymyślał. Praktyczny zestaw instrukcji:
TODO in the spec and list it under ASSUMPTIONS.”Error) and reference them.”Po wygenerowaniu przejrzyj najpierw sekcję ASSUMPTIONS — tam zaczyna się drift, jeśli zaakceptujesz domysły.
Zanim porównasz ze środowiskiem produkcyjnym, najpierw upewnij się, że plik OpenAPI jest spójny wewnętrznie:
To pozwala wykryć „życzeniowe” specyfikacje jeszcze przed porównaniem z implementacją.
Traktuj uruchamiane API jako to, czego użytkownicy doświadczają dziś, i podejmuj decyzje przypadek po przypadku:
Trzymaj zmiany małe (jeden endpoint, jedna odpowiedź), żeby łatwiej było przetestować.
Walidacja po stronie serwera powinna odrzucać żądania, które naruszają kontrakt, i zwracać jasny, spójny błąd (status + kod/kształt błędu).
Walidacja po stronie klienta powinna wykryć zmiany łamiące kompatybilność wcześnie, asercjami skupionymi na tym, na czym naprawdę polega funkcja:
Unikaj asercji na wszystkie pola opcjonalne, żeby testy sygnalizowały realne problemy, nie nieszkodliwe dodatki.
Praktyczny rytuał, który działa bez spowalniania zespołu:
Jeśli pracujesz w Koder.ai, możesz trzymać plik OpenAPI obok kodu, robić snapshoty przed ryzykownymi zmianami i cofnąć się, gdy diff będzie mylący.