/** * Einheitliche API-Antwort-Helfer (plan.md: "HTTP-Statuscodes korrekt * verwenden", "saubere Fehlerbehandlung"). */ import { NextResponse } from 'next/server'; import { ZodError } from 'zod'; import { UnauthorizedError } from '@/lib/auth/session'; import { ReservationConflictError, ReservationValidationError, } from '@/lib/reservations/conflicts'; import { MaxDurationExceededError, CalendarInactiveError, ReservationNotFoundError, } from '@/lib/reservations/service'; /** 400: Validierungsfehler mit lesbaren Meldungen. */ export function validationErrorResponse(error: ZodError): NextResponse { const messages = error.issues.map((issue) => issue.message).join(' '); return NextResponse.json({ error: messages }, { status: 400 }); } /** 401: Nicht angemeldet. */ export function unauthorizedResponse(): NextResponse { return NextResponse.json({ error: 'Nicht angemeldet.' }, { status: 401 }); } /** 403: Angemeldet, aber keine Berechtigung. */ export function forbiddenResponse(): NextResponse { return NextResponse.json( { error: 'Keine Berechtigung fuer diese Aktion.' }, { status: 403 }, ); } /** 404: Ressource nicht gefunden (oder bewusst verschleiert). */ export function notFoundResponse(message = 'Nicht gefunden.'): NextResponse { return NextResponse.json({ error: message }, { status: 404 }); } /** 409: Zeitkollision. */ export function conflictResponse(): NextResponse { return NextResponse.json( { error: 'Der gewuenschte Zeitraum ist bereits belegt.' }, { status: 409 }, ); } /** * Mappt bekannte Fehler auf korrekte HTTP-Statuscodes. * Unbekannte Fehler werden geloggt und als 500 gemeldet, ohne * interne Details preiszugeben. */ export function errorResponse(error: unknown): NextResponse { if (error instanceof ZodError) { return validationErrorResponse(error); } if (error instanceof UnauthorizedError) { return unauthorizedResponse(); } if (error instanceof ReservationConflictError) { return conflictResponse(); } // Validierungsfehler (Vergangenheit, Start>=Ende): 400 mit Meldung. if (error instanceof ReservationValidationError) { return NextResponse.json({ error: error.message }, { status: 400 }); } // Dauer ueberschritten: 400 mit lesbare Meldung (nicht 500). if (error instanceof MaxDurationExceededError) { return NextResponse.json({ error: error.message }, { status: 400 }); } // Kalender deaktiviert/nicht gefunden: 403 (Berechtigung/Status). if (error instanceof CalendarInactiveError) { return NextResponse.json({ error: error.message }, { status: 403 }); } // Reservierung nicht gefunden: 404. if (error instanceof ReservationNotFoundError) { return notFoundResponse(error.message); } console.error('[api] Unerwarteter Fehler:', error); return NextResponse.json( { error: 'Ein interner Fehler ist aufgetreten.' }, { status: 500 }, ); }