Przejdź do głównej zawartości

Wzorce rozwoju API

Wzorce rozwoju API dla asystentów AI rozwiązują awarie ujawniające się na produkcji: middleware z kluczem idempotencji powstrzymujący ponowione żądania POST przed podwójnym obciążeniem, paginację kursorem typu keyset sortowaną po kluczu złożonym, która nie gubi wierszy na granicy strony, oraz specyfikacje OpenAPI generowane ze schematów Zod, dzięki czemu kontrakt nie rozjeżdża się z kodem.

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 te wzorce API zawodzą na produkcji” 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.