Files
nexarch/internal/apiserver/errors.go
sysopsandClaude Sonnet 5 27f9866264 API-01: rest-api-grundgeruest-versionierung
internal/apiserver: Server.Handle(version, pattern, h) registriert Routen
unter /api/{version}/... (Akzeptanzkriterium 1) — verschiedene Versionen
sind unabhaengige Pfade im ServeMux, eine neue Version beeintraechtigt
bestehende nicht. HandleV1 ist die Kurzform fuer die aktuelle Hauptversion.

Einheitliches Fehlerschema {"error":{"code","message"}} ueber WriteError
(Akzeptanzkriterium 2) — bewusst NICHT auth.RequireAuth aus IAM-02
wiederverwendet, da dessen Klartext-Fehlerantworten nicht zum einheitlichen
JSON-Schema passen wuerden; stattdessen authAndTenantContext nutzt
auth.TokenIssuer.Verify direkt (dieselbe Kryptographie, keine Duplikation)
und antwortet im API-01-Schema, auch bei 401.

authAndTenantContext ist die Middleware, die JEDEM ueber Handle registrierten
Endpunkt Tenant-/Benutzerkontext bereitstellt (Akzeptanzkriterium 3, ueber
apiserver.FromContext abrufbar) — kein Handler prueft Auth selbst.
loggingMiddleware protokolliert jede Anfrage strukturiert.

Pruefungen (ausgefuehrt auf root@192.168.1.131, go build/vet/test PASS):
1. Fehlerhafte Anfrage liefert ueber mehrere Endpunkte hinweg dasselbe
   Fehlerschema (Stichprobe) — TestErrorFormat_ConsistentAcrossEndpoints:
   zwei unabhaengige Endpunkte, beide liefern 401 im identischen
   {"error":{"code","message"}}-Schema. PASS.
2. Middleware-Kette nachweislich von jedem Endpunkt durchlaufen —
   TestMiddleware_SetsRequestContextForEveryEndpoint: zwei Endpunkte lesen
   RequestContext, beide erhalten korrekten UserID/TenantSlug aus dem Token. PASS.
3. Versionswechsel (fiktive v2-Route) ohne v1 zu beeintraechtigen —
   TestVersioning_V2DoesNotAffectV1: v1 vor und nach Anlage von v2 liefert
   unveraendert dieselbe Antwort. PASS.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-27 21:32:27 +02:00

32 lines
943 B
Go

// Package apiserver implementiert Core API-01: das REST-Grundgerüst mit
// URL-Versionierung, einheitlichem Fehlerformat und Middleware-Kette
// (Auth, Tenant-/Benutzerkontext, Logging).
package apiserver
import (
"encoding/json"
"net/http"
)
// errorBody ist das EINE Fehlerschema fuer alle Endpunkte unter /api/{version}/
// (Akzeptanzkriterium 2).
type errorBody struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
// WriteError schreibt einen Fehler im einheitlichen Schema. code ist ein
// stabiler, maschinenlesbarer Bezeichner (z.B. "unauthenticated"), message
// ein fuer Menschen lesbarer deutscher Text.
func WriteError(w http.ResponseWriter, status int, code, message string) {
var body errorBody
body.Error.Code = code
body.Error.Message = message
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(body)
}