KoderKoder.ai
CennikDla firmEdukacjaDla inwestorów
Zaloguj sięRozpocznij

Produkt

CennikDla firmDla inwestorów

Zasoby

Skontaktuj się z namiPomoc technicznaEdukacjaBlog

Informacje prawne

Polityka prywatnościWarunki użytkowaniaBezpieczeństwoZasady dopuszczalnego użytkowaniaZgłoś nadużycie

Social media

LinkedInTwitter
Koder.ai
Język

© 2026 Koder.ai. Wszelkie prawa zastrzeżone.

Strona główna›Blog›Wzorce obsługi błędów API w Go dla jasnych, spójnych odpowiedzi
29 wrz 2025·6 min

Wzorce obsługi błędów API w Go dla jasnych, spójnych odpowiedzi

Wzorce obsługi błędów w API w Go, które standaryzują typowane błędy, mapowanie na kody HTTP, identyfikatory żądań i bezpieczne komunikaty bez ujawniania szczegółów wewnętrznych.

Wzorce obsługi błędów API w Go dla jasnych, spójnych odpowiedzi

Dlaczego niespójne błędy API irytują klientów

Gdy każdy endpoint raportuje błędy inaczej, klienci przestają ufać Twojemu API. Jeden endpoint zwraca { "error": "not found" }, inny { "message": "missing" }, a jeszcze inny wysyła zwykły tekst. Nawet jeśli znaczenie jest podobne, kod klienta musi teraz zgadywać, co się stało.

Koszty pojawiają się szybko. Zespoły tworzą kruche logiki parsowania i dorzucają wyjątki dla każdego endpointu. Ponawianie żądań staje się ryzykowne, bo klient nie wie, czy „spróbuj ponownie później”, czy „Twoje dane są błędne”. Liczba zgłoszeń do wsparcia rośnie, bo klient widzi niejasny komunikat, a Twój zespół nie może łatwo dopasować go do linii logów po stronie serwera.

Typowy scenariusz: aplikacja mobilna wywołuje trzy endpointy podczas rejestracji. Pierwszy zwraca HTTP 400 z mapą błędów pól, drugi zwraca HTTP 500 ze stringiem śladu stosu, a trzeci zwraca HTTP 200 z { "ok": false }. Zespół aplikacji wypuszcza trzy różne handlery błędów, a Twój backend nadal dostaje raporty typu „rejestracja czasem nie działa” bez jasnego punktu startu.

Cel jest prosty: jedna przewidywalna umowa. Klienci powinni móc niezawodnie odczytać, co się stało, czy to ich wina, czy Twoja, czy warto spróbować ponownie, i mieć identyfikator żądania, który mogą wkleić do zgłoszenia.

Uwaga: dotyczy to JSON-owych API HTTP (nie gRPC), ale te same idee mają zastosowanie wszędzie tam, gdzie zwracasz błędy do innych systemów.

Prosty cel: jedna umowa, której przestrzega każdy endpoint

Wybierz jedną jasną umowę dla błędów i spraw, by każdy endpoint jej przestrzegał. „Spójne” oznacza ten sam kształt JSON, to samo znaczenie pól i takie samo zachowanie niezależnie od tego, który handler zawodzi. Gdy to zrobisz, klienci przestaną zgadywać i zaczną obsługiwać błędy poprawnie.

Użyteczna umowa pomaga klientom zdecydować, co robić dalej. Dla większości aplikacji każda odpowiedź z błędem powinna odpowiedzieć na trzy pytania:

  • Czy mogę naprawić dane wejściowe?
  • Czy warto spróbować ponownie później?
  • Czy muszę skontaktować się ze wsparciem?

Praktyczny zestaw zasad:

  • Jeden schemat odpowiedzi dla wszystkich błędów.
  • Jedna polityka kodów statusu (ten sam typ błędu zawsze mapuje do tego samego HTTP status).
  • Jedna polityka bezpiecznych komunikatów (co użytkownik widzi vs co pozostaje wewnętrzne).
  • Jeden hak korelacyjny (identyfikator żądania zwracany, aby wsparcie mogło znaleźć awarię).

Zdecyduj z góry, co nigdy nie powinno się pojawić w odpowiedziach. Do typowych „nigdy” należą fragmenty SQL, ślady stosu, wewnętrzne nazwy hostów, sekrety i surowe stringi błędów z zależności.

Utrzymuj wyraźny podział: krótki komunikat dla użytkownika (bezpieczny, grzeczny, wskazujący sposób działania) oraz szczegóły wewnętrzne (pełny błąd, stack, kontekst) przechowywane w logach. Na przykład „Nie udało się zapisać zmian. Spróbuj ponownie.” jest bezpieczne. „pq: duplicate key value violates unique constraint users_email_key” nie jest.

Gdy każdy endpoint przestrzega tej samej umowy, klienci mogą zbudować jeden handler błędów i używać go wszędzie.

Zdefiniuj schemat odpowiedzi o błędzie, na którym klienci mogą polegać

Klienci mogą obsługiwać błędy czysto tylko wtedy, gdy każdy endpoint odpowiada w tym samym kształcie. Wybierz jedną otoczkę JSON i utrzymuj ją stabilną.

Praktycznym domyślnym wyborem jest obiekt error plus top-level request_id:

{
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Some fields are invalid.",
    "details": {
      "fields": {
        "email": "must be a valid email address"
      }
    }
  },
  "request_id": "req_01HV..."
}

HTTP status daje szeroką kategorię (400, 401, 409, 500). Maszynowo czytelne error.code daje konkretny przypadek, po którym klient może się rozgałęziać. To rozdzielenie ma znaczenie, bo wiele różnych problemów dzieli ten sam status. Aplikacja mobilna może pokazać inną UI dla EMAIL_TAKEN vs WEAK_PASSWORD, nawet jeśli oba są 400.

Trzymaj error.message bezpieczny i przyjazny. Powinien pomóc użytkownikowi naprawić problem, ale nigdy nie ujawniać wnętrza (SQL, ślady stosu, nazwy providerów, ścieżki plików).

Pola opcjonalne są przydatne, jeśli pozostają przewidywalne:

  • Błędy walidacji: details.fields jako mapa pola -> komunikat.
  • Limity i problemy tymczasowe: details.retry_after_seconds.
  • Dodatkowa pomoc: details.docs_hint jako zwykły tekst (nie URL).

Dla kompatybilności wstecznej traktuj wartości error.code jako część kontraktu API. Dodawaj nowe kody bez zmiany starych znaczeń. Dodawaj tylko pola opcjonalne i zakładaj, że klienci zignorują nieznane im pola.

Typowane błędy w Go: czysty model dla handlerów

Obsługa błędów robi się chaotyczna, gdy każdy handler wymyśla własny sposób sygnalizowania niepowodzenia. Mały zestaw typowanych błędów to naprawia: handlery zwracają znane typy błędów, a jedna warstwa odpowiedzialna za odpowiedzi zamienia je na spójne odpowiedzi.

Praktyczny zestaw startowy obejmuje większość endpointów:

  • ValidationError (błędne dane wejściowe)
  • NotFoundError (zasób nie istnieje)
  • ConflictError (naruszenie unikalności, rozbieżność stanu)
  • UnauthorizedError (niezalogowany lub brak uprawnień)
  • InternalError (wszystko inne)

Klucz to stabilność na najwyższym poziomie, nawet jeśli pierwotna przyczyna się zmienia. Możesz owijać niższe błędy (SQL, sieć, parsowanie JSON), jednocześnie zwracając ten sam publiczny typ, który middleware potrafi wykryć.

type NotFoundError struct {
	Resource string
	ID       string
	Err      error // private cause
}

func (e NotFoundError) Error() string { return "not found" }
func (e NotFoundError) Unwrap() error { return e.Err }

W handlerze zwróć NotFoundError{Resource: "user", ID: id, Err: err} zamiast bezpośrednio ujawniać sql.ErrNoRows.

Do sprawdzania błędów preferuj errors.As dla typów niestandardowych i errors.Is dla sentinel errors. Sentinel errors (np. var ErrUnauthorized = errors.New("unauthorized")) działają w prostych przypadkach, ale typy niestandardowe wygrywają, gdy potrzebujesz bezpiecznego kontekstu (np. którego zasobu nie znaleziono) bez zmiany publicznego kontraktu odpowiedzi.

Bądź rygorystyczny co do tego, co dołączasz:

  • Publiczne (bezpieczne dla klientów): krótki komunikat, stabilny kod i czasami nazwa pola dla walidacji.
  • Prywatne (tylko logi): podlegająca przyczyna Err, informacje o stacku, surowe błędy SQL, tokeny, dane użytkownika.

Ten podział pozwala pomagać klientom bez ujawniania wnętrza.

Mapowanie typów błędów na kody statusu HTTP w sposób spójny

Gdy masz już typowane błędy, następne zadanie jest nudne, ale niezbędne: ten sam typ błędu powinien zawsze generować ten sam HTTP status. Klienci zbudują wokół tego logikę.

Praktyczne mapowanie, które pasuje do większości API:

Typ błędu (przykład)StatusKiedy używać
BadRequest (uszkodzony JSON, brak wymaganych parametrów query)400Żądanie jest na poziomie protokołu lub formatu niepoprawne.
Unauthenticated (brak/nieprawidłowy token)401Klient musi się uwierzytelnić.
Forbidden (brak uprawnień)403Auth jest poprawny, ale dostęp zabroniony.
NotFound (ID zasobu nie istnieje)404Żądany zasób nie istnieje (lub decydujesz się ukryć istnienie).
Conflict (naruszenie unikalności, rozbieżność wersji)409Żądanie poprawne, ale koliduje z aktualnym stanem.
ValidationFailed (reguły pola)422Kształt JSON jest OK, ale biznesowa walidacja zawiodła.
RateLimited429Zbyt wiele żądań w oknie czasowym.
Internal (nieoczekiwany błąd)500Bug lub nieprzewidziane niepowodzenie.
Unavailable (zależność padła, timeout, konserwacja)503Tymczasowy problem po stronie serwera.

Dwie rozróżnienia zapobiegają dużo zamieszania:

  • 400 vs 422: użyj 400, gdy nie da się wiarygodnie zinterpretować żądania (zły JSON, złe typy). Użyj 422, gdy możesz je sparsować, ale wartości są nieakceptowalne.
  • 409 vs 422: używaj 422 dla walidacji pól (np. za krótkie hasło). Używaj 409, gdy dane są poprawne, ale nie można ich zastosować z powodu stanu (adres e-mail już zajęty, zamówienie już wysłane, błąd optimistic lock).

Wskazówki co do ponawiania:

  • Zwykle bezpieczne do ponowienia: 503, a czasem 429 (po odczekaniu).
  • Zwykle niebezpieczne do ponawiania bez zmian: 400, 401, 403, 404, 409, 422.
  • Jeśli operacja jest idempotentna (PUT z tym samym body lub POST z idempotency key), ponawianie staje się bezpieczniejsze nawet po błędach przejściowych.

Identyfikatory żądań: najszybszy sposób na debugowanie problemów klientów

Zaplanuj swój kontrakt błędów
Sporządź spójny kontrakt JSON dla błędów i politykę identyfikatorów żądań w trybie planowania Koder.ai.
Wypróbuj za darmo

Request ID to krótka, unikalna wartość identyfikująca jedno wywołanie API end-to-end. Jeśli klienci widzą go w każdej odpowiedzi, wsparcie staje się proste: „Prześlij mi request ID” często wystarcza, by znaleźć dokładne logi i konkretną awarię.

Ten zwyczaj opłaca się zarówno dla odpowiedzi sukcesu, jak i błędów.

Zasady generowania i propagacji

Stosuj prostą regułę: jeśli klient wysyła identyfikator żądania, zachowaj go. Jeśli nie, stwórz nowy.

  • Akceptuj przychodzący ID z jednego nagłówka (wybierz jeden i go udokumentuj, np. X-Request-Id).
  • Jeśli nagłówek brak lub jest pusty, wygeneruj nowy ID na krawędzi (middleware) i dołącz go do kontekstu żądania.
  • Nigdy nie zmieniaj ID w trakcie żądania. Przekazuj je do wywołań downstream (DB, inne usługi) przez context lub nagłówki.

Umieść request ID w trzech miejscach:

  • Nagłówek odpowiedzi (ten sam nagłówek, który akceptujesz)
  • Ciało odpowiedzi (jako request_id w standardowym schemacie)
  • Logi (jako pole strukturalne w każdej linii loga)

Praca wsadowa i asynchroniczna

Dla endpointów batchowych lub zadań backgroundowych trzymaj nadrzędny request ID. Przykład: klient przesyła 200 wierszy, 12 nie przechodzi walidacji i enqueujesz pracę. Zwróć jeden request_id dla całego wywołania i dołącz parent_request_id do każdej pracy i do każdego błędu per-item. Dzięki temu możesz odtworzyć „jedno upload” nawet gdy rozbija się ono na wiele zadań.

Logowanie i metryki bez wycieku wnętrza

Klienci potrzebują jasnej, stabilnej odpowiedzi o błędzie. Twoje logi potrzebują brudnej prawdy. Trzymaj te dwa światy rozdzielone: zwróć klientowi bezpieczny komunikat i publiczny kod błędu, a w logach zapisz wewnętrzną przyczynę, stack i kontekst serwera.

Loguj jeden zdarzenie strukturalne dla każdej odpowiedzi z błędem, możliwe do wyszukania po request_id.

Pola warte zachowania w spójny sposób:

  • request_id
  • user_id lub account_id (gdy uwierzytelniony)
  • publiczny kod błędu i HTTP status
  • nazwa handlera/route i metoda
  • wewnętrzne szczegóły błędu (owinięta przyczyna, błędy walidacji pól, timeout upstream)

Przechowuj szczegóły wewnętrzne tylko w logach serwera (lub w wewnętrznym magazynie błędów). Klient nigdy nie powinien widzieć surowych błędów bazy danych, zapytań SQL, śladów stosu ani komunikatów providerów. Jeśli masz wiele usług, pole wewnętrzne takie jak source (api, db, auth, upstream) może przyspieszyć triage.

Obserwuj hałaśliwe endpointy i błędy rate-limited. Jeśli endpoint może generować ten sam 429 lub 400 tysiące razy na minutę, unikaj spamowania logów: próbkuj powtarzające się zdarzenia albo obniżaj poziom severności dla oczekiwanych błędów, jednocześnie zliczając je w metrykach.

Metryki wykrywają problemy wcześniej niż logi. Śledź liczniki pogrupowane po HTTP status i kodzie błędu i ustaw alerty na nagły wzrost. Jeśli RATE_LIMITED wzrośnie 10x po deployu, zobaczysz to szybko, nawet gdy logi są próbkowane.

Krok po kroku: wdrażanie spójnego pipeline'u błędów w Go

Od kodu do wdrożenia
Wdróż usługę i zachowaj spójność odpowiedzi o błędach między środowiskami.
Wdróż aplikację

Najprostszy sposób na osiągnięcie spójności błędów to przestać obsługiwać je „wszędzie” i przepuszczać przez mały pipeline. Ten pipeline decyduje, co klient zobaczy, a co trafi do logów.

Pipeline w 5 praktycznych krokach

Zacznij od małego zestawu kodów błędów, na których klienci mogą polegać (np.: INVALID_ARGUMENT, NOT_FOUND, UNAUTHORIZED, CONFLICT, INTERNAL). Owiń je w typowany błąd, który ujawnia tylko bezpieczne, publiczne pola (code, safe message, opcjonalne details jak które pole jest niepoprawne). Trzymaj prywatne przyczyny ukryte.

Następnie zaimplementuj jedną funkcję translatora, która zamienia dowolny błąd w (statusCode, responseBody). To tutaj typowane błędy mapowane są na kody HTTP, a nieznane błędy stają się bezpieczną odpowiedzią 500.

Dalej dodaj middleware, które:

  • zapewnia, że każde żądanie ma request_id
  • odzyskuje z panic

Panic nie powinien nigdy wypluć śladu stosu do klienta. Zwróć normalną odpowiedź 500 z generickim komunikatem i zaloguj pełny panic z tym samym request_id.

Na koniec zmień handlery, aby zwracały error zamiast bezpośrednio pisać odpowiedź. Jeden wrapper może wywołać handler, uruchomić translator i zapisać JSON w standardowym formacie.

Krótka lista kontrolna:

  • Zdefiniuj typowane błędy z bezpiecznymi polami i stabilnymi kodami.
  • Tłumacz błędy na statusy i JSON odpowiedzi w jednym miejscu.
  • Dodaj middleware dla request ID i odzyskiwania z panic.
  • Spraw, by handlery zwracały błędy, nie odpowiedzi.
  • Dodaj golden tests dla translatora i wrappera.

Golden tests są ważne, bo zamykają kontrakt. Jeśli ktoś później zmieni komunikat lub kod statusu, testy padną zanim klienci zostaną zaskoczeni.

Przykład: jeden endpoint, trzy awarie, przewidywalne odpowiedzi

Wyobraź sobie endpoint tworzący rekord klienta.

POST /v1/customers z JSON jak { "email": "[email protected]", "name": "Pat" }. Serwer zawsze zwraca ten sam kształt błędu i zawsze zawiera request_id.

1) Błąd walidacji (400)

Brakuje e-maila lub jest źle sformatowany. Klient może oznaczyć pole.

{
  "request_id": "req_01HV9N2K6Q7A3W1J9K8B",
  "error": {
    "code": "VALIDATION_FAILED",
    "message": "Some fields need attention.",
    "details": {
      "fields": {
        "email": "must be a valid email address"
      }
    }
  }
}

2) Konflikt (409)

E-mail już istnieje. Klient może zasugerować logowanie albo wybór innego e-maila.

{
  "request_id": "req_01HV9N3C2D0F0M3Q7Z9R",
  "error": {
    "code": "ALREADY_EXISTS",
    "message": "A customer with this email already exists."
  }
}

3) Błąd przejściowy (503)

Zależność jest niedostępna. Klient może spróbować ponownie z backoffem i wyświetlić spokojny komunikat.

{
  "request_id": "req_01HV9N3X8P2J7T4N6C1D",
  "error": {
    "code": "TEMPORARILY_UNAVAILABLE",
    "message": "We could not save your request right now. Please try again."
  }
}

Z jedną umową klient reaguje konsekwentnie:

  • 400: oznacz pola używając details.fields
  • 409: poprowadź użytkownika do bezpiecznego następnego kroku
  • 503: zasugeruj ponowienie i pokaż request_id jako identyfikator do wsparcia

Dla wsparcia ten sam request_id to najszybsza droga do prawdziwej przyczyny w logach, bez ujawniania śladów stosu czy błędów bazy.

Typowe pułapki, które pogarszają obsługę błędów

Najszybszy sposób, by zirytować klientów API, to zmuszać ich do zgadywania. Jeśli jeden endpoint zwraca { "error": "..." }, a inny { "message": "..." }, każdy klient zamienia się w stos wyjątków, a błędy chowają się tygodniami.

Kilka częstych błędów:

  • Zwracanie HTTP 200 z błędem w ciele, albo przełączanie między wieloma schematami błędów w różnych endpointach.
  • Ujawnianie wnętrza w wiadomości użytkownika, jak błędy SQL, ślady stosu, IP, nazwy hostów zależności lub ścieżki plików.
  • Używanie tekstu human-friendly jako jedynego identyfikatora, zamiast stabilnego code, po którym klient może kluczyć.
  • Zmiana kodów błędów bez zastanowienia (lub używanie tego samego kodu dla różnych problemów), co łamie klientów napisanych dla starego zachowania.
  • Dodawanie request_id tylko przy błędach, więc nie da się skorelować zgłoszenia użytkownika z wcześniejszym udanym wywołaniem.

Ujawnianie wnętrza to najłatwiejsza pułapka. Handler zwraca err.Error() bo tak wygodnie, a potem nazwa constraintu lub komunikat zewnętrznej biblioteki trafia do produkcji. Trzymaj komunikat dla klienta bezpieczny i krótki, a szczegółową przyczynę w logach.

Poleganie wyłącznie na tekście to powolne gnicie. Jeśli klient musi parsować po angielsku zdania typu „email already exists”, nie możesz zmieniać brzmienia bez łamania logiki. Stabilne kody błędów pozwalają zmieniać i tłumaczyć komunikaty, zachowując niezmienną logikę.

Traktuj kody błędów jako część kontraktu publicznego. Jeśli musisz zmienić kod, dodaj nowy i utrzymaj stary przez jakiś czas, nawet jeśli oba mapują do tego samego HTTP status.

Na koniec: dołączaj to samo pole request_id do każdej odpowiedzi, sukcesu i błędu. Gdy użytkownik mówi „działało, potem przestało”, ten jeden ID często oszczędza godzinę zgadywania.

Szybka lista kontrolna przed wypuszczeniem

Zarządzaj kodem backendu
Zachowaj pełną kontrolę, eksportując wygenerowany kod źródłowy Go w dowolnym momencie.
Eksportuj źródło

Przed release zrób szybki przegląd spójności:

  • Jeden kształt błędu wszędzie. Każdy endpoint zwraca te same pola JSON (np.: error.code, error.message, request_id).
  • Stabilne kody błędów i pokrycie. Trzymaj kody krótkie i nudne (VALIDATION_FAILED, NOT_FOUND, CONFLICT, UNAUTHORIZED). Dodaj testy, by handlery nie mogły zwracać nieznanych kodów przez przypadek.
  • Jedna reguła mapowania statusów. Zdecyduj, jak każdy typ błędu mapuje się na HTTP status i stosuj to w jednym wspólnym miejscu.
  • Request ID w obu kierunkach. Zawsze zwracaj request_id i loguj go dla każdego żądania, włącznie z panic i timeoutami.
  • Domyślnie bezpieczne komunikaty. Komunikaty dla użytkownika powinny być krótkie, jasne i użyteczne; nigdy nie zawierać śladów stosu, błędów SQL ani nazw vendorów.

Po tym ręcznie sprawdź kilka endpointów: wywołaj błąd walidacji, brak rekordu i nieoczekiwany błąd. Jeśli odpowiedzi różnią się między endpointami (zmieniają się pola, statusy dryfują, komunikaty wyciekają), napraw wspólny pipeline zanim dodasz więcej funkcji.

Praktyczna zasada: jeśli komunikat mógłby pomóc atakującemu lub zmylić zwykłego użytkownika, należy go trzymać w logach, nie w odpowiedzi.

Następne kroki: ustandaryzuj teraz i utrzymuj spójność później

Spisz kontrakt błędów, którego chcesz, by każdy endpoint przestrzegał, nawet jeśli Twoje API jest już live. Wspólny kontrakt (status, stabilny kod błędu, bezpieczny komunikat i request_id) to najszybszy sposób, by uczynić błędy przewidywalnymi dla klientów.

Następnie migracja stopniowa. Zachowaj istniejące handlery, ale przekieruj ich błędy przez jednego mappera, który zamienia wewnętrzne błędy w publiczny kształt odpowiedzi. To poprawia spójność bez ryzykownego „big rewrite” i zapobiega nowym endpointom wymyślania formatów.

Prowadź mały katalog kodów błędów i traktuj go jak część API. Gdy ktoś chce dodać nowy kod, rób krótki przegląd: czy to naprawdę nowy przypadek, czy nazwa jest jasna i czy mapuje do właściwego statusu?

Dodaj kilka testów, które wykryją dryf:

  • Każda odpowiedź błędu zawiera request_id.
  • Kod statusu pasuje do typu błędu (nie do tekstu błędu).
  • error.code jest obecny i pochodzi z katalogu.
  • error.message pozostaje bezpieczny i nigdy nie zawiera wewnętrznych szczegółów.
  • Nieznane błędy fallbackują do 500 z generycznym komunikatem.

Jeśli budujesz backend w Go od zera, warto zablokować kontrakt wcześnie. Na przykład, Koder.ai (koder.ai) zawiera tryb planowania, w którym możesz zdefiniować konwencje jak schema błędów i katalog kodów na początku, a potem utrzymać zgodność handlerów w miarę rozwoju API.

Często zadawane pytania

Jak powinna wyglądać „spójna odpowiedź z błędem”?

Użyj jednego kształtu JSON dla każdej odpowiedzi z błędem, w całym API. Praktycznym domyślnym wyborem jest top-level request_id plus obiekt error z polami code, message i opcjonalnym details, aby klienci mogli niezawodnie parsować i reagować.

Jak unikać wycieku szczegółów wewnętrznych w błędach API?

Zwracaj error.message jako krótkie, bezpieczne dla użytkownika zdanie i trzymaj prawdziwą przyczynę w logach serwera. Nie zwracaj surowych błędów bazy danych, śladów stosu, wewnętrznych hostów ani komunikatów zależności, nawet jeśli podczas developmentu wydają się pomocne.

Czy naprawdę potrzebuję kodu błędu, jeśli mam już kody HTTP?

Użyj stabilnego error.code do logiki maszynowej, a pozwól kodowi HTTP opisać szeroką kategorię. Klienci powinni rozgałęziać się po error.code (np. ALREADY_EXISTS), a status traktować jako wskazówkę (np. 409 oznacza konflikt stanu).

Kiedy użyć HTTP 400 zamiast 422?

Użyj 400, gdy żądanie nie da się niezawodnie sparsować lub zinterpretować (uszkodzony JSON, złe typy). Użyj 422, gdy żądanie jest poprawne składniowo, ale narusza reguły biznesowe (niepoprawny format e-mail, za krótkie hasło).

Kiedy użyć HTTP 409 zamiast 422?

Użyj 409, gdy wejście jest poprawne, ale nie można go zastosować z powodu konfliktu stanu (adres e-mail już zajęty, rozbieżność wersji). Użyj 422 dla walidacji na poziomie pola, gdzie zmiana wartości naprawia problem bez zmiany stanu serwera.

Jak typowane błędy w Go pomagają utrzymać spójność odpowiedzi?

Stwórz mały zestaw typowanych błędów (walidacja, nie znaleziono, konflikt, nieautoryzowany, wewnętrzny) i pozwól handlerom je zwracać. Następnie użyj jednego wspólnego translatora, który mapuje te typy na kody statusu i standardowy kształt odpowiedzi JSON.

Jak generować i zwracać identyfikatory żądań?

Zawsze zwracaj request_id w każdej odpowiedzi, sukcesie lub błędzie, i loguj go w każdej linii loga serwera. Gdy klient zgłasza problem, ten identyfikator powinien wystarczyć, by znaleźć dokładną ścieżkę błędu w logach.

Dlaczego zwracanie HTTP 200 z `{ "ok": false }` to zły pomysł?

Zwracaj 200 tylko wtedy, gdy operacja się powiodła; używaj 4xx/5xx dla błędów. Ukrywanie błędów za 200 zmusza klientów do parsowania pól w ciele odpowiedzi i tworzy niespójne zachowanie między endpointami.

Które błędy powinny być ponawiane przez klientów, a które nie?

Domyślnie nie ponawiaj żądań dla 400, 401, 403, 404, 409 i 422, bo bez zmian żądania ponowne próby nie pomogą. Pozwól na ponawianie dla 503 i czasami 429 po odczekaniu; jeśli wspierasz klucze idempotentności, ponawianie dla POST przy błędach przejściowych staje się bezpieczniejsze.

Jak zapobiec dryfowaniu odpowiedzi z błędami w miarę ewolucji API?

Zamknij kontrakt kilkoma „golden” testami, które sprawdzają status, error.code i obecność request_id. Dodawaj nowe kody błędów bez zmiany starych znaczeń i tylko dodawaj pola opcjonalne, aby starsi klienci dalej działali.

Spis treści
Dlaczego niespójne błędy API irytują klientówProsty cel: jedna umowa, której przestrzega każdy endpointZdefiniuj schemat odpowiedzi o błędzie, na którym klienci mogą polegaćTypowane błędy w Go: czysty model dla handlerówMapowanie typów błędów na kody statusu HTTP w sposób spójnyIdentyfikatory żądań: najszybszy sposób na debugowanie problemów klientówLogowanie i metryki bez wycieku wnętrzaKrok po kroku: wdrażanie spójnego pipeline'u błędów w GoPrzykład: jeden endpoint, trzy awarie, przewidywalne odpowiedziTypowe pułapki, które pogarszają obsługę błędówSzybka lista kontrolna przed wypuszczeniemNastępne kroki: ustandaryzuj teraz i utrzymuj spójność późniejCzęsto zadawane pytania
Udostępnij
Koder.ai
Build your own app with Koder today!

The best way to understand the power of Koder is to see it for yourself.

Start FreeBook a Demo