/** * API handler utilities with configurable error handling */ import { NextResponse } from "next/server"; import { ApiError, TableNotFoundError } from "./errors"; export interface HandlerOptions { headers?: HeadersInit; } export interface HandlerConfig { /** * Optional callback to transform errors before the default handling. * Return an ApiError to use custom handling, or undefined to use default handling. */ onError?: (error: unknown) => ApiError | undefined; } /** * Create an API handler wrapper with configurable error handling * * @example * // Basic usage * const withHandler = createApiHandler(); * * // With custom error handling * const withHandler = createApiHandler({ * onError: (error) => { * if (isCustomError(error)) { * return new CustomApiError(); * } * return undefined; // Use default handling * } * }); */ export function createApiHandler(config?: HandlerConfig) { return async function withHandler( handler: () => Promise, options?: HandlerOptions, ): Promise { const headers = options?.headers; try { const result = await handler(); return NextResponse.json(result, { headers }); } catch (error) { // Handle our custom API errors if (error instanceof ApiError) { return NextResponse.json(error.toJSON(), { status: error.status, headers, }); } // Try custom error handling if provided if (config?.onError) { const customError = config.onError(error); if (customError) { return NextResponse.json(customError.toJSON(), { status: customError.status, headers, }); } } // Handle table not found errors if (error instanceof Error && error.message.includes("no such table")) { const tableMatch = error.message.match(/no such table: (\w+)/); const tableName = tableMatch?.[1] || "unknown"; const tableError = new TableNotFoundError(tableName); return NextResponse.json(tableError.toJSON(), { status: tableError.status, headers, }); } // Log and return generic error for unexpected issues console.error("[API Error]:", error); return NextResponse.json( { error: "INTERNAL_ERROR", message: "Internal server error" }, { status: 500, headers }, ); } }; }