Build a Full JSON API in app/api
Route Handlers — Deep Dive
`route.ts` files give you full HTTP-method handlers with NextRequest and NextResponse helpers — enough to build a complete JSON API.
What you'll learn
- Export GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS handlers
- Read params, query, and body
- Set cookies and status on the response
Route Handlers are how you build APIs in App Router. Each app/.../route.ts file owns
its URL; you export a function per HTTP method and Next does the wiring.
A Full CRUD Handler
// app/api/posts/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function GET(
req: NextRequest,
{ params }: { params: Promise<{ id: string }> },
) {
const { id } = await params
const post = await db.post.findUnique({ where: { id } })
if (!post) return NextResponse.json({ error: 'not found' }, { status: 404 })
return NextResponse.json(post)
}
export async function PATCH(
req: NextRequest,
{ params }: { params: Promise<{ id: string }> },
) {
const { id } = await params
const body = await req.json()
const post = await db.post.update({ where: { id }, data: body })
return NextResponse.json(post)
}
export async function DELETE(
req: NextRequest,
{ params }: { params: Promise<{ id: string }> },
) {
const { id } = await params
await db.post.delete({ where: { id } })
return new NextResponse(null, { status: 204 })
} Reading Query Strings
export async function GET(req: NextRequest) {
const q = new URL(req.url).searchParams.get('q') ?? ''
const results = await db.post.findMany({ where: { title: { contains: q } } })
return NextResponse.json(results)
} Setting Cookies and Status
export async function POST(req: NextRequest) {
const res = NextResponse.json({ ok: true })
res.cookies.set('session', 'abc', {
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 60 * 60 * 24,
})
return res
} Build NextResponse first, mutate its cookies and headers, then return it.