import { NextResponse } from 'next/server';
import { z } from 'zod';
const Body = z.object({ name: z.string().min(2).max(80) });
function getUserId(req: Request) {
const auth = req.headers.get('authorization');
if (!auth?.startsWith('Bearer ')) return null;
return auth.slice('Bearer '.length);
}
export async function POST(req: Request) {
const userId = getUserId(req);
if (!userId) return NextResponse.json({ error: 'UNAUTHORIZED' }, { status: 401 });
const json = await req.json();
const parsed = Body.safeParse(json);
if (!parsed.success) {
return NextResponse.json(
{ error: 'VALIDATION_ERROR', issues: parsed.error.issues },
{ status: 400 }
);
}
const created = { id: crypto.randomUUID?.() ?? 'temp', name: parsed.data.name, ownerId: userId };
return NextResponse.json(created, { status: 201 });
}
I like API routes that read like tiny, well-scoped controllers. In Next.js Route Handlers, I keep auth and input parsing right at the top, then return explicit status codes instead of throwing for expected failures. I also avoid leaking server-only details: clients get a stable error code and a request id for support, while the real stack trace stays in logs. The main benefit is readability: auth → validation → business operation → response. When every route follows the same structure, onboarding is faster and audits are easier because you can scan for the usual footguns (missing auth, missing validation, inconsistent errors) without spelunking.