Script Valley
Next.js: Full-Stack React Applications
API Routes and Server ActionsLesson 3.5

How to structure Next.js API routes for REST endpoints

REST conventions in App Router, dynamic route handlers, CORS headers, error handling patterns, HTTP status codes, route handler middleware patterns

RESTful Route Handler Structure

For a full CRUD REST API, use two route files:

app/api/posts/
  route.ts          ← GET (list) + POST (create)
  [id]/
    route.ts        ← GET (single) + PATCH + DELETE
// app/api/posts/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server'

export async function GET(
  _req: NextRequest,
  { params }: { params: { id: string } }
) {
  const post = await db.post.findUnique({ where: { id: params.id } })
  if (!post) return NextResponse.json({ error: 'Not found' }, { status: 404 })
  return NextResponse.json(post)
}

export async function DELETE(
  _req: NextRequest,
  { params }: { params: { id: string } }
) {
  await db.post.delete({ where: { id: params.id } })
  return new NextResponse(null, { status: 204 })
}

Adding CORS Headers

export async function OPTIONS() {
  return new NextResponse(null, {
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
      'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    },
  })
}

The second argument to route handler functions provides params for dynamic segments. This is different from page components where params comes via the first argument props. Return 204 No Content for successful deletes with no body.