Przejdź do głównej zawartości

Wzorce rozwoju API

Twój endpoint POST /orders obciąża klientów dwukrotnie, gdy aplikacja mobilna ponawia żądanie przy niestabilnym połączeniu. Twoja paginacja kursorem po cichu gubi wiersze, gdy dwa rekordy mają to samo created_at. A specyfikacja OpenAPI, którą napisałeś ręcznie, rozjechała się z kodem trzy sprinty temu, więc wygenerowany klient kłamie każdemu frontendowcowi, który mu ufa. To są te błędy API, które przechodzą przez code review i wychodzą na jaw dopiero na produkcji — i właśnie tu agent AI zarabia na siebie, bo poprawka to znany wzorzec, a nie akt twórczy.

Ten przepis pokazuje prompty, które zamieniają „AI naszkicowało trasę” w „trasa jest idempotentna, prawidłowo paginowana i udokumentowana ze źródła prawdy”. Jako bazowy stack przyjmujemy Express + TypeScript + Zod, ale prompty przenoszą się bez problemu na Fastify, NestJS czy Route Handlers w Next.js.

  • Gotowy do wklejenia prompt, który generuje middleware z kluczem idempotencji, dzięki czemu ponowienia po stronie klienta nigdy nie obciążą dwukrotnie.
  • Prompt do paginacji kursorem ze stabilnym sortowaniem złożonym, które nie gubi wierszy.
  • Prompt OpenAPI 3.1 z handlerów, który wyprowadza specyfikację z Twoich schematów Zod, więc nie może się rozjechać.
  • Trójnarzędziowy workflow szkicowania endpointu (Cursor, Claude Code, Codex) i kiedy które narzędzie błyszczy.
  • Listę kontrolną „Gdy to się psuje” dla trybów awaryjnych, w jakie te wygenerowane przez AI wzorce wpadają na produkcji.

Pierwszy ruch przy każdym nowym endpoincie jest taki sam: podaj agentowi swoje istniejące konwencje tras i pozwól mu je dopasować. Narzędzia różnią się tym, jak to napędzasz — inline w edytorze, w terminalu albo nieinteraktywnie w CI.

Otwórz plik routera, by znalazł się w kontekście, następnie otwórz tryb Agent (Cmd/Ctrl + I) i odwołaj się do pliku jawnie:

Korzystając z konwencji w @src/routes/users.ts, dodaj trasę POST /orders do @src/routes/orders.ts. Zwaliduj ciało żądania schematem Zod (items: array of {sku, qty}, idempotencyKey: uuid), zwróć 201 z utworzonym zamówieniem oraz 409 przy zduplikowanym kluczu idempotencji. Podłącz to do istniejącego middleware obsługi błędów — nie wymyślaj nowych klas błędów.

Tryb Agent edytuje plik w miejscu i pokazuje diff dla każdego pliku. Użyj Checkpoints przed zaakceptowaniem, abyś mógł cofnąć całą zmianę, jeśli kształt walidacji jest błędny.

Idempotentne endpointy: poprawka na podwójne obciążenie

Dział zatytułowany „Idempotentne endpointy: poprawka na podwójne obciążenie”

Ponowiony POST to klasyczna pułapka systemów rozproszonych. Rozwiązaniem jest middleware z kluczem idempotencji, które zapisuje pierwszą odpowiedź i odtwarza ją przy każdym powtórzeniu tego samego klucza. To na tyle mechaniczne, że AI robi to poprawnie — o ile powiesz mu, gdzie przechowywać klucz i jak długo go trzymać.

Gdy AI odda Ci to z powrotem, zweryfikuj dwie rzeczy, zanim mu zaufasz. Po pierwsze, blokadę w trakcie przetwarzania (in-flight lock): naiwna wersja zapisuje odpowiedź dopiero po zakończeniu handlera, więc dwa równoczesne ponowienia oba chybiają cache i oba obciążają. Wpis odtworzenia musi zostać zarezerwowany (np. SET idem:{key} "processing" NX), zanim handler się wykona. Po drugie, TTL kontra okno biznesowe: 24-godzinny TTL oznacza, że ponowienie drugiego dnia i tak obciąży dwukrotnie. Poproś AI, by uczyniło to okno jawnym i dopasowanym do polityki ponawiania Twojego klienta.

Paginacja offsetowa (?page=3&limit=20) jest w porządku dla tabeli administracyjnej, ale rozsypuje się przy zapisach: wstaw wiersz, gdy użytkownik przegląda strony, a wszystko się przesuwa. Paginacja kursorem to produkcyjna odpowiedź, a błąd, który modele AI niezawodnie wprowadzają, to sortowanie po kolumnie nieunikalnej. Jeśli dwa zamówienia mają to samo created_at, kursor oparty na samym created_at pominie lub powtórzy wiersze na granicy strony.

Sygnałem, że AI zrobiło to poprawnie, jest predykat złożony. WHERE created_at < $1 jest błędne; WHERE (created_at, id) < ($1, $2) jest poprawne. Jeśli zobaczysz gdziekolwiek OFFSET w wygenerowanym zapytaniu, odrzuć je — to ten błąd, którego przyszedłeś tu uniknąć.

Ręcznie utrzymywany OpenAPI się rozjeżdża. Trwałym rozwiązaniem jest wyprowadzenie specyfikacji z tych samych schematów Zod, którymi Twoje handlery i tak walidują, dzięki czemu kontrakt i runtime nie mogą się rozejść. Biblioteki takie jak @asteasolutions/zod-to-openapi czynią z tego krok generowania, a nie równoległy dokument.

Sprawdzenie nieaktualności w CI to część, która sprawia, że to się utrzymuje. Bez niej specyfikacja regeneruje się tylko wtedy, gdy ktoś pamięta, i wracasz do rozjazdu. Z nią zmiana schematu, która nie regeneruje dokumentu, wywala build.