KoderKoder.ai
PreiseEnterpriseBildungFür Investoren
AnmeldenLoslegen

Produkt

PreiseEnterpriseFür Investoren

Ressourcen

Kontakt aufnehmenSupportBildungBlog

Rechtliches

DatenschutzrichtlinieNutzungsbedingungenSicherheitRichtlinie zur akzeptablen NutzungMissbrauch melden

Soziales

LinkedInTwitter
Koder.ai
Sprache

© 2026 Koder.ai. Alle Rechte vorbehalten.

Startseite›Blog›Fehlerbehandlungsmuster für Go-APIs — klare, konsistente Antworten
29. Sept. 2025·6 Min

Fehlerbehandlungsmuster für Go-APIs — klare, konsistente Antworten

Go-API-Fehlerbehandlungsmuster: typisierte Fehler, konsistente HTTP-Statuszuordnung, Request-IDs und sichere Meldungen ohne interne Details zu leaken.

Fehlerbehandlungsmuster für Go-APIs — klare, konsistente Antworten

Warum inkonsistente API-Fehler Clients frustrieren

Wenn jeder Endpunkt Fehler anders meldet, verlieren Clients das Vertrauen in deine API. Eine Route gibt { "error": "not found" } zurück, eine andere { "message": "missing" }, und eine dritte sendet reinen Text. Selbst wenn die Bedeutung ähnlich ist, muss der Client-Code nun raten, was passiert ist.

Die Kosten zeigen sich schnell. Teams bauen fragile Parsing-Logik und fügen pro Endpunkt Sonderfälle hinzu. Retries werden riskant, weil der Client nicht unterscheiden kann, ob er es später noch einmal versuchen sollte oder ob die Eingabe falsch ist. Support-Tickets steigen, weil der Client nur eine vage Nachricht sieht und dein Team die Antwort nicht leicht mit einer Server-Logzeile abgleichen kann.

Ein typisches Szenario: Eine Mobile-App ruft während der Registrierung drei Endpunkte auf. Der erste gibt HTTP 400 mit einer feldbezogenen Fehlermap zurück, der zweite HTTP 500 mit einem Stacktrace-String, und der dritte HTTP 200 mit { "ok": false }. Das App-Team liefert drei verschiedene Error-Handler, und dein Backend-Team erhält trotzdem Meldungen wie „Signup schlägt manchmal fehl“ ohne klaren Startpunkt.

Das Ziel ist ein vorhersehbarer Vertrag. Clients sollten zuverlässig lesen können, was passiert ist: ob es an ihrer Eingabe lag, ob ein Retry sinnvoll ist und welche Request-ID sie an den Support weitergeben können.

Hinweis zum Umfang: Das richtet sich auf JSON-HTTP-APIs (nicht gRPC), aber dieselben Ideen gelten überall dort, wo du Fehler an andere Systeme zurückgibst.

Ein einfaches Ziel: ein Vertrag, dem jeder Endpunkt folgt

Wähle einen klaren Fehlervertrag und sorge dafür, dass jeder Endpunkt ihn einhält. „Konsistent“ bedeutet dieselbe JSON-Form, dieselbe Semantik der Felder und dasselbe Verhalten, unabhängig davon, welcher Handler fehlschlägt. Sobald das steht, hören Clients auf zu raten und beginnen, Fehler richtig zu behandeln.

Ein nützlicher Vertrag hilft Clients zu entscheiden, wie sie weiter vorgehen. Für die meisten Apps sollte jede Fehlerantwort drei Fragen beantworten:

  • Kann ich meine Eingabe korrigieren?
  • Sollte ich später noch einmal versuchen?
  • Muss ich den Support kontaktieren?

Eine praktische Regelmenge:

  • Eine Antwort-Schema für alle Fehler.
  • Eine Statuscode-Policy (ein Fehler-Typ mappt immer auf denselben HTTP-Status).
  • Eine Policy für sichere Meldungen (was Nutzer sehen dürfen vs. was intern bleibt).
  • Ein Korrelations-Hook (eine Request-ID, die Support zur Auffindung des Fehlers nutzen kann).

Entscheide vorher, was niemals in Antworten auftauchen darf. Häufige „Nie“-Punkte sind SQL-Fragmente, Stacktraces, interne Hostnamen, Secrets und rohe Fehlermeldungen von Abhängigkeiten.

Halte eine saubere Trennung: eine kurze, nutzerfreundliche Nachricht (sicher, höflich, handlungsorientiert) und interne Details (voller Fehler, Stack und Kontext) nur in Logs. Zum Beispiel ist „Konnte deine Änderungen nicht speichern. Bitte versuche es erneut.“ sicher. „pq: duplicate key value violates unique constraint users_email_key“ ist es nicht.

Wenn jeder Endpunkt demselben Vertrag folgt, kann der Client einen einzigen Error-Handler bauen und überall wiederverwenden.

Definiere ein Fehler-Antwortschema, auf das Clients sich verlassen können

Clients können Fehler nur sauber behandeln, wenn jeder Endpunkt dieselbe Form zurückgibt. Wähle einen JSON-Envelope und halte ihn stabil.

Ein praktisches Default ist ein error-Objekt plus eine 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...\"
}

Der HTTP-Status gibt die grobe Kategorie an (400, 401, 409, 500). Der maschinenlesbare error.code gibt den konkreten Fall an, auf den der Client verzweigen kann. Diese Trennung ist wichtig, weil viele verschiedene Probleme denselben Status teilen. Eine Mobile-App kann für EMAIL_TAKEN eine andere UI zeigen als für WEAK_PASSWORD, auch wenn beides 400 ist.

Halte error.message sicher und menschenverständlich. Sie sollte dem Nutzer helfen, das Problem zu beheben, darf aber niemals Interna leaken (SQL, Stacktraces, Provider-Namen, Dateipfade).

Optionale Felder sind nützlich, wenn sie vorhersehbar bleiben:

  • Validierungsfehler: details.fields als Map von Feld zu Nachricht.
  • Rate-Limiting oder temporäre Probleme: details.retry_after_seconds.
  • Zusätzliche Hinweise: details.docs_hint als Klartext (keine URL).

Für Abwärtskompatibilität: Behandle error.code-Werte als Teil deines API-Vertrags. Füge neue Codes hinzu, ohne alte Bedeutungen zu verändern. Füge nur optionale Felder hinzu und erwarte, dass Clients unbekannte Felder ignorieren.

Typisierte Fehler in Go: ein sauberes Modell für deine Handler

Fehlerbehandlung wird unübersichtlich, wenn jeder Handler seine eigene Art erfindet, Fehlschläge zu signalisieren. Eine kleine Menge typisierter Fehler behebt das: Handler geben bekannte Fehlertypen zurück, und eine einzige Response-Schicht macht daraus konsistente Antworten.

Ein praktisches Starter-Set deckt die meisten Endpunkte ab:

  • ValidationError (ungültige Eingabe)
  • NotFoundError (Resource fehlt)
  • ConflictError (Unique-Constraint, Zustandsmismatch)
  • UnauthorizedError (nicht eingeloggt oder nicht berechtigt)
  • InternalError (alles andere)

Der Schlüssel ist Stabilität auf oberster Ebene, selbst wenn die Root-Ursache sich ändert. Du kannst unterliegende Fehler (SQL, Netzwerk, JSON-Parsing) wrappen und trotzdem denselben öffentlichen Typ zurückgeben, den Middleware erkennen kann.

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 }

Gib in deinem Handler NotFoundError{Resource: "user", ID: id, Err: err} zurück, anstatt sql.ErrNoRows direkt durchzureichen.

Zum Überprüfen von Fehlern verwende errors.As für benutzerdefinierte Typen und errors.Is für Sentinel-Errors. Sentinel-Errors (wie var ErrUnauthorized = errors.New("unauthorized")) funktionieren für einfache Fälle, aber benutzerdefinierte Typen gewinnen, wenn du sicheren Kontext brauchst (z. B. welche Ressource fehlt), ohne deinen öffentlichen Antwortvertrag zu ändern.

Sei streng bei dem, was du anhängst:

  • Öffentlich (sicher für Clients): eine kurze Nachricht, ein stabiler Code und manchmal ein Feldname bei Validierung.
  • Privat (nur Logs): unterliegende Err, Stack-Info, rohe SQL-Fehler, Tokens, Nutzerdaten.

Diese Trennung ermöglicht es dir, Clients zu helfen, ohne Interna offenzulegen.

Fehler-Typen konsistent auf HTTP-Statuscodes abbilden

Wenn du typisierte Fehler hast, ist die nächste Aufgabe langweilig, aber wichtig: derselbe Fehler-Typ sollte immer denselben HTTP-Status erzeugen. Clients bauen Logik darauf auf.

Eine praktikable Zuordnung, die für die meisten APIs funktioniert:

Fehler-Typ (Beispiel)StatusWann verwenden
BadRequest (fehlerhaftes JSON, fehlender Query-Param)400Die Anfrage ist auf Protokoll- oder Format-Ebene ungültig.
Unauthenticated (kein/ungültiger Token)401Der Client muss sich authentifizieren.
Forbidden (keine Berechtigung)403Auth ist gültig, aber Zugriff nicht erlaubt.
NotFound (Ressource existiert nicht)404Die angeforderte Ressource ist nicht vorhanden (oder du verbirgst die Existenz).
Conflict (Unique-Constraint, Versionskonflikt)409Die Anfrage ist wohlgeformt, kollidiert aber mit dem aktuellen Zustand.
ValidationFailed (Feldregeln)422Die Form ist ok, aber Geschäftsvalidierung schlägt fehl (E-Mail-Format, Mindestlänge).
RateLimited429Zu viele Anfragen in einem Zeitfenster.
Internal (unbekannter Fehler)500Bug oder unerwarteter Fehler.
Unavailable (Abhängigkeit down, Timeout, Wartung)503Temporäres serverseitiges Problem.

Zwei Unterscheidungen, die viel Verwirrung verhindern:

  • 400 vs 422: Verwende 400, wenn die Anfrage nicht zuverlässig interpretierbar ist (schlechtes JSON, falsche Typen). Verwende 422, wenn du sie parsen kannst, die Werte aber nicht akzeptabel sind.
  • 409 vs 422: Verwende 422 für feldbezogene Validierung (Passwort zu kurz). Verwende 409, wenn die Daten gültig sind, aber nicht angewendet werden können wegen des Zustands (E-Mail bereits vergeben, Bestellung bereits versandt, optimistischer Sperrfehler).

Retry-Hinweise sind wichtig:

  • Normalerweise sicher zu retryen: 503, und manchmal 429 (nach Wartezeit).
  • Normalerweise nicht sicher zu retryen ohne Änderungen: 400, 401, 403, 404, 409, 422.
  • Ist die Operation idempotent (PUT mit demselben Body oder POST mit Idempotency-Key), werden Retries auch nach transienten Fehlern sicherer.

Request-IDs: der schnellste Weg, Client-Probleme zu debuggen

Vom Code zum Deployment
Deploye deinen Service und halte Fehlerantworten konsistent über Umgebungen hinweg.
Service deployen

Eine Request-ID ist ein kurzer, eindeutiger Wert, der einen API-Aufruf von Anfang bis Ende identifiziert. Wenn Clients ihn in jeder Antwort sehen können, wird Support einfach: „Schick mir die Request-ID“ reicht oft, um die genaue Logzeile und den Fehler zu finden.

Diese Gewohnheit zahlt sich sowohl bei Erfolgs- als auch bei Fehlerantworten aus.

Regeln zur Erzeugung und Weitergabe

Verwende eine klare Regel: Wenn der Client eine Request-ID sendet, behalte sie. Wenn nicht, erzeuge eine neue.

  • Akzeptiere eine eingehende ID über einen einzelnen Header-Namen (wähle einen und dokumentiere ihn, z. B. X-Request-Id).
  • Ist der Header fehlend oder leer, generiere eine neue ID am Rand (Middleware) und hänge sie an den Request-Context.
  • Ändere die ID niemals mitten im Request. Gib sie an nachgelagerte Aufrufe (DB, andere Services) über Context oder Header weiter.

Setze die Request-ID an drei Stellen:

  • Response-Header (derselbe Header-Name, den du akzeptierst)
  • Response-Body (als request_id in deinem Standard-Schema)
  • Logs (als strukturiertes Feld auf jeder Logzeile)

Batch- und asynchrone Arbeit

Bei Batch-Endpunkten oder Hintergrundjobs behalte eine Parent-Request-ID. Beispiel: Ein Client lädt 200 Zeilen hoch, 12 validieren nicht, und du enqueuest Arbeit. Gib eine request_id für den gesamten Aufruf zurück und füge jedem Job und jedem per-Item-Error eine parent_request_id hinzu. So kannst du „einen Upload“ nachverfolgen, auch wenn er in viele Tasks zerfällt.

Logging und Metriken ohne Interna zu leaken

Clients brauchen eine klare, stabile Fehlerantwort. Deine Logs brauchen die ungeschönte Wahrheit. Halte diese beiden Welten getrennt: gib dem Client eine sichere Nachricht und einen öffentlichen Fehlercode, während du die interne Ursache, Stack und Kontext auf dem Server loggst.

Logge für jede Fehlerantwort ein strukturiertes Event, durchsuchbar nach request_id.

Felder, die konsistent gehalten werden sollten:

  • request_id
  • user_id oder account_id (wenn authentifiziert)
  • öffentlicher Fehlercode und HTTP-Status
  • Handler/Route-Name und Methode
  • interne Fehlerdetails (gewrapptes Ursache-Error, Validierungsfeldfehler, Upstream-Timeout)

Speichere interne Details nur in Server-Logs (oder einem internen Fehler-Store). Der Client sollte niemals rohe Datenbankfehler, Query-Text, Stacktraces oder Provider-Meldungen sehen. Wenn du mehrere Services betreibst, kann ein internes Feld wie source (api, db, auth, upstream) die Triage beschleunigen.

Beobachte laute Endpunkte und rate-limitete Fehler. Wenn ein Endpunkt tausende 429- oder 400-Antworten pro Minute produzieren kann, vermeide Log-Spam: sample wiederkehrende Events oder senke die Schwere für erwartete Fehler, während du sie trotzdem in Metriken zählst.

Metriken entdecken Probleme früher als Logs. Tracke Zählungen gruppiert nach HTTP-Status und Fehlercode und alarmiere bei plötzlichen Spitzen. Wenn RATE_LIMITED nach einem Deploy um das 10-fache ansteigt, siehst du das schnell, selbst wenn Logs gesamplet sind.

Schritt für Schritt: eine konsistente Fehler-Pipeline in Go implementieren

Plane deinen Fehlervertrag
Entwerfe einen konsistenten JSON-Fehlervertrag und eine Request-ID-Policy im Koder.ai-Planungsmodus.
Kostenlos testen

Der einfachste Weg, Fehler konsistent zu machen, ist aufzuhören, sie überall individuell zu behandeln, und sie durch eine kleine Pipeline zu leiten. Diese Pipeline entscheidet, was der Client sieht und was du in Logs behältst.

Die Pipeline in 5 praktischen Schritten

Starte mit einer kleinen Menge Fehlercodes, auf die sich Clients verlassen können (z. B.: INVALID_ARGUMENT, NOT_FOUND, UNAUTHORIZED, CONFLICT, INTERNAL). Wrapp diese in typisierte Fehler, die nur sichere, öffentliche Felder (code, sichere Nachricht, optionale Details wie welches Feld falsch ist) freigeben. Bewahre interne Ursachen privat.

Implementiere dann eine einzige Übersetzerfunktion, die jeden Fehler in (statusCode, responseBody) verwandelt. Hier werden typisierte Fehler auf HTTP-Statuscodes gemappt, und unbekannte Fehler werden zu einer sicheren 500-Antwort.

Füge anschließend Middleware hinzu, die:

  • sicherstellt, dass jede Anfrage eine request_id hat
  • von Panics erholt (recover)

Ein Panic darf niemals Stacktraces an den Client ausgeben. Gib eine normale 500-Antwort mit einer generischen Nachricht zurück und logge den vollen Panic mit derselben request_id.

Ändere schließlich deine Handler so, dass sie error zurückgeben statt die Response direkt zu schreiben. Ein Wrapper kann den Handler aufrufen, den Übersetzer ausführen und JSON im Standard-Format schreiben.

Eine kompakte Checkliste:

  • Definiere typisierte Fehler mit sicheren Feldern und stabilen Codes.
  • Übersetze Fehler an einer Stelle in Statuscodes und Response-JSON.
  • Füge Request-ID- und Panic-Recovery-Middleware hinzu.
  • Lass Handler Fehler zurückgeben, nicht Responses schreiben.
  • Schreibe Golden-Tests für den Übersetzer und den Wrapper.

Golden-Tests sind wichtig, weil sie den Vertrag festschreiben. Wenn später jemand eine Nachricht oder einen Statuscode ändert, schlagen die Tests fehl, bevor Clients überrascht werden.

Beispiel: ein Endpunkt, drei Fehler, vorhersehbare Antworten

Stell dir einen Endpunkt vor: Eine Client-App legt einen Customer-Datensatz an.

POST /v1/customers mit JSON wie { "email": "[email protected]", "name": "Pat" }. Der Server gibt immer dieselbe Fehlerform zurück und immer eine request_id.

1) Validierungsfehler (400)

Die E-Mail fehlt oder ist fehlerhaft formatiert. Der Client kann das Feld hervorheben.

{
  \"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)

Die E-Mail existiert bereits. Der Client kann zum Anmelden raten oder eine andere E-Mail vorschlagen.

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

3) Transienter Fehler (503)

Eine Abhängigkeit ist down. Der Client kann mit Backoff retryen und eine ruhige Nachricht anzeigen.

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

Mit einem Vertrag reagiert der Client konsistent:

  • 400: Felder mit details.fields markieren
  • 409: den Nutzer zu einer sicheren nächsten Aktion führen
  • 503: zum Retry auffordern und die request_id als Support-ID anzeigen

Für den Support ist dieselbe request_id der schnellste Weg zur echten Ursache in internen Logs, ohne Stacktraces oder Datenbankfehler offenzulegen.

Häufige Fallen, die Fehlerbehandlung verschlimmern

Der schnellste Weg, API-Clients zu verärgern, ist sie raten zu lassen. Wenn ein Endpunkt { "error": "..." } zurückgibt und ein anderer { "message": "..." }, wird jeder Client zu einem Haufen Sonderfälle und Bugs bleiben wochenlang verborgen.

Einige Fehler treten immer wieder auf:

  • HTTP 200 mit einer Fehler-Nachricht im Body zurückgeben oder zwischen mehreren Fehler-Schemas wechseln.
  • Interna in der Nutzer-Nachricht offenbaren, wie SQL-Fehler, Stacktraces, IPs, Hostnamen von Abhängigkeiten oder Dateipfade.
  • Nur menschenlesbaren Text als Identifier nutzen statt eines stabilen code, an dem Clients sich orientieren können.
  • Fehlercodes ungeprüft ändern (oder denselben Code für unterschiedliche Probleme wiederverwenden) und so Clients brechen.
  • request_id nur bei Fehlern hinzufügen, sodass du einen User-Report nicht mit dem vorherigen erfolgreichen Aufruf korrelieren kannst.

Interna zu leaken ist die leichteste Falle. Ein Handler gibt err.Error() zurück, weil es praktisch ist, und dann landet ein Constraint-Name oder eine Drittanbieter-Meldung in Produktions-Antworten. Halte die Client-Nachricht kurz und sicher und lege die ausführliche Ursache in die Logs.

Sich nur auf Text zu verlassen, ist ein schleichendes Problem. Wenn der Client englische Sätze wie „email already exists" parsen muss, kannst du die Formulierung nicht ändern, ohne Logik zu brechen. Stabile Fehlercodes erlauben dir, Nachrichten anzupassen, zu übersetzen und Verhalten konsistent zu halten.

Behandle Fehlercodes als Teil deines öffentlichen Vertrags. Musst du einen Code ändern, füge einen neuen hinzu und halte den alten vorerst weiter verfügbar, auch wenn beide denselben HTTP-Status haben.

Schließlich: Füge in jede Antwort dasselbe request_id-Feld ein, Erfolg wie Fehler. Wenn ein Nutzer sagt „es hat funktioniert, dann ging es kaputt“, spart diese eine ID oft eine Stunde Rätselraten.

Schnell-Checkliste bevor du ausrollst

Werde für das Bauen belohnt
Teile, was du gebaut hast, mit Koder.ai und erhalte Credits zum Weitermachen.
Credits verdienen

Vor dem Release eine kurze Konsistenzprüfung:

  • Eine Fehler-Form überall. Jeder Endpunkt gibt dieselben JSON-Felder zurück (z. B. error.code, error.message, request_id).
  • Stabile Fehlercodes mit Abdeckung. Halte Codes kurz und langweilig (VALIDATION_FAILED, NOT_FOUND, CONFLICT, UNAUTHORIZED). Schreibe Tests, damit Handler nicht versehentlich unbekannte Codes zurückgeben.
  • Eine zentrale Status-Mapping-Regel. Entscheide, wie jeder Fehler-Typ auf einen HTTP-Status abgebildet wird, und wende das an einer gemeinsamen Stelle an.
  • Request-ID in beide Richtungen. Gib immer eine request_id zurück und logge sie für jede Anfrage, inkl. Panics und Timeouts.
  • Sichere Nachrichten per Default. Nutzerfeundliche Messages sollten kurz, klar und handlungsorientiert sein – niemals Stacktraces, SQL-Fehler oder Vendor-Namen.

Danach spot-checke einige Endpunkte manuell. Erzeuge einen Validierungsfehler, einen Missing-Record-Fehler und einen unerwarteten Fehler. Wenn Antworten zwischen Endpunkten unterschiedlich aussehen (Felder wechseln, Statuscodes driften, Nachrichten Interna zeigen), behebe die gemeinsame Pipeline, bevor du neue Funktionen hinzufügst.

Eine praktische Regel: Wenn eine Nachricht einem Angreifer helfen würde oder einen normalen Nutzer verwirrt, gehört sie in die Logs, nicht in die Antwort.

Nächste Schritte: jetzt standardisieren und später konsistent bleiben

Schreibe den Fehlervertrag auf, dem jeder Endpunkt folgen soll, auch wenn deine API schon live ist. Ein geteilter Vertrag (Status, stabiler Fehlercode, sichere Nachricht und request_id) ist der schnellste Weg, Fehler für Clients vorhersehbar zu machen.

Migriere dann schrittweise. Behalte bestehende Handler bei, leite aber ihre Fehler durch einen Mapper, der interne Fehler in deine öffentliche Antwortform überführt. Das erhöht die Konsistenz ohne riskanten Big-Rewrite und verhindert, dass neue Endpunkte neue Formate erfinden.

Führe einen kleinen Fehlercode-Katalog und behandle ihn wie Teil deiner API. Wenn jemand einen neuen Code einführen will, prüfe kurz: Ist er wirklich neu, ist die Benennung klar, und mappt er auf den richtigen HTTP-Status?

Füge einige Tests hinzu, die Drift erkennen:

  • Jede Fehlerantwort enthält request_id.
  • Statuscode passt zum Fehler-Typ (nicht zur Fehlermeldung).
  • error.code ist vorhanden und stammt aus dem Katalog.
  • error.message bleibt sicher und enthält keine internen Details.
  • Unbekannte Fehler fallen auf eine 500 mit generischer Nachricht zurück.

Wenn du ein Go-Backend von Grund auf aufbaust, hilft es, den Vertrag früh zu fixieren. Zum Beispiel enthält Koder.ai (koder.ai) einen Planungsmodus, in dem du Konventionen wie ein Fehler-Schema und einen Code-Katalog vorab definieren kannst, um Handler beim Wachsen der API im Takt zu halten.

FAQ

What should a “consistent error response” look like?

Verwende überall dieselbe JSON-Struktur für Fehlerantworten. Ein praktisches Default ist eine top-level request_id plus ein error-Objekt mit code, message und optionalen details, sodass Clients zuverlässig parsen und reagieren können.

How do I avoid leaking internal details in API errors?

Gib error.message als kurzen, für Nutzer sicheren Satz zurück und bewahre die eigentliche Ursache in den Server-Logs auf. Gib niemals rohe Datenbankfehler, Stacktraces, interne Hostnamen oder Nachrichten von Drittanbietern zurück – auch wenn das in der Entwicklung hilfreich wirkt.

Do I really need an error code if I already have HTTP status codes?

Verwende einen stabilen error.code für maschinelle Logik und lasse den HTTP-Status die grobe Kategorie beschreiben. Clients sollten sich auf error.code (z. B. ALREADY_EXISTS) stützen und den Status als Richtwert (z. B. 409 für Konflikte) nutzen.

When should I use HTTP 400 vs 422?

Verwende 400, wenn die Anfrage nicht zuverlässig geparst oder interpretiert werden kann (fehlerhaftes JSON, falsche Typen). Nutze 422, wenn die Anfrage wohlgeformt ist, aber Geschäftsregeln verletzt (ungültiges E-Mail-Format, zu kurzes Passwort).

When should I use HTTP 409 vs 422?

Nutze 409, wenn die Eingabe gültig ist, aber nicht angewendet werden kann, weil sie mit dem aktuellen Zustand kollidiert (E-Mail bereits vergeben, Versionskonflikt). Verwende 422 für feldbezogene Validierung, bei der das Ändern des Felds das Problem löst, ohne dass sich der Serverzustand ändern muss.

How do typed errors in Go help keep responses consistent?

Erzeuge eine kleine Menge typisierter Fehler (Validation, NotFound, Conflict, Unauthorized, Internal) und lasse Handler diese zurückgeben. Ein gemeinsamer Übersetzer mappt dann diese Typen auf Statuscodes und die standardisierte JSON-Antwortform.

How should I generate and return request IDs?

Gib in jeder Antwort eine request_id zurück, Erfolg wie Fehler, und logge sie in jeder Server-Logzeile. Wenn ein Client ein Problem meldet, reicht diese ID oft, um den genauen Fehlerpfad in den Logs zu finden.

Why is returning HTTP 200 with `{ "ok": false }` a bad idea?

Gib 200 nur zurück, wenn die Operation erfolgreich war. Verwende 4xx/5xx für Fehler. Fehler hinter 200 zu verstecken zwingt Clients, Body-Felder zu parsen, und erzeugt inkonsistentes Verhalten zwischen Endpunkten.

Which errors should clients retry, and which should they not?

Standardmäßig nicht retryen für 400, 401, 403, 404, 409 und 422, da ein Retry ohne Änderung in der Regel nicht hilft. Erlaube Retry für 503 und manchmal für 429 nach Wartezeit; wenn du Idempotenz-Keys unterstützt, werden Retries für POST bei transienten Fehlern sicherer.

How do I prevent error responses from drifting as the API evolves?

Sichere den Vertrag mit einigen „golden“ Tests, die Status, error.code und Vorhandensein von request_id prüfen. Füge neue Fehlercodes hinzu, ohne alte Bedeutungen zu ändern, und füge nur optionale Felder hinzu, damit ältere Clients weiter funktionieren.

Inhalt
Warum inkonsistente API-Fehler Clients frustrierenEin einfaches Ziel: ein Vertrag, dem jeder Endpunkt folgtDefiniere ein Fehler-Antwortschema, auf das Clients sich verlassen könnenTypisierte Fehler in Go: ein sauberes Modell für deine HandlerFehler-Typen konsistent auf HTTP-Statuscodes abbildenRequest-IDs: der schnellste Weg, Client-Probleme zu debuggenLogging und Metriken ohne Interna zu leakenSchritt für Schritt: eine konsistente Fehler-Pipeline in Go implementierenBeispiel: ein Endpunkt, drei Fehler, vorhersehbare AntwortenHäufige Fallen, die Fehlerbehandlung verschlimmernSchnell-Checkliste bevor du ausrollstNächste Schritte: jetzt standardisieren und später konsistent bleibenFAQ
Teilen
Koder.ai
Erstellen Sie Ihre eigene App mit Koder heute!

Der beste Weg, die Leistungsfähigkeit von Koder zu verstehen, ist es selbst zu erleben.

Kostenlos startenDemo buchen