import { NextResponse } from "next/server"; import { ZodError } from "@/lib/validierung"; import { logger } from "@/lib/logger"; import { AnwendungsFehler } from "@/server/fehler"; /** * Einheitliche Fehlerantwort der REST-API – Web-GUI und CLI lesen dasselbe Format: * `{ fehler: { code, nachricht, hinweis?, felder? } }`. */ export type FehlerAntwort = { fehler: { code: string; nachricht: string; hinweis?: string; felder?: Record }; }; export function fehlerAntwort(fehler: unknown): NextResponse { if (fehler instanceof AnwendungsFehler) { return NextResponse.json( { fehler: { code: fehler.code, nachricht: fehler.message, ...(fehler.hinweis ? { hinweis: fehler.hinweis } : {}), ...(fehler.felder ? { felder: fehler.felder } : {}), }, }, { status: fehler.status }, ); } if (fehler instanceof ZodError) { const felder: Record = {}; for (const problem of fehler.issues) { const pfad = problem.path.join(".") || "_"; felder[pfad] ??= problem.message; } return NextResponse.json( { fehler: { code: "ungueltig", nachricht: "Die Eingaben sind nicht vollständig oder ungültig.", felder, }, }, { status: 400 }, ); } logger.error({ err: fehler }, "Unerwarteter Fehler in der API"); return NextResponse.json({ fehler: { code: "intern", nachricht: "Interner Fehler." } }, { status: 500 }); } /** Umhüllt einen Route Handler: wandelt geworfene Fehler in das einheitliche Format. */ export function api( handler: (...argumente: A) => Promise, ): (...argumente: A) => Promise { return async (...argumente: A) => { try { return await handler(...argumente); } catch (fehler) { return fehlerAntwort(fehler); } }; } /** Liest einen JSON-Rumpf; ein kaputter Rumpf ist ein 400, kein 500. */ export async function jsonLesen(anfrage: Request): Promise { try { return await anfrage.json(); } catch { throw new AnwendungsFehler(400, "kein_json", "Der Anfragerumpf ist kein gültiges JSON."); } }