Using Next.js Route Handlers: A Complete Guide
What Are Next.js Route Handlers?
Setting Up Your First Route Handler
1import { NextResponse } from 'next/server';2 3export async function GET() {4 return NextResponse.json({ message: 'Hello, Route Handlers!' });5}6 7export async function POST(request: Request) {8 const data = await request.json();9 return NextResponse.json({ received: data }, { status: 201 });10}Working with Dynamic Routes
1// app/api/posts/[id]/route.ts2import { NextResponse } from 'next/server';3 4export async function GET(5 request: Request,6 { params }: { params: { id: string } }7) {8 const postId = params.id;9 return NextResponse.json({ id: postId, title: 'Sample Post' });10}11 12export async function PUT(13 request: Request,14 { params }: { params: { id: string } }15) {16 const updates = await request.json();17 return NextResponse.json({ id: params.id, ...updates });18}19 20export async function DELETE(21 request: Request,22 { params }: { params: { id: string } }23) {24 return NextResponse.json({ success: true, id: params.id });25}Handling Request Data
1import { NextRequest, NextResponse } from 'next/server';2 3export async function POST(request: NextRequest) {4 // Access query parameters5 const searchParams = request.nextUrl.searchParams;6 const action = searchParams.get('action');7 8 // Access headers9 const contentType = request.headers.get('content-type');10 const authorization = request.headers.get('authorization');11 12 // Read request body13 const body = await request.json();14 const { email, name } = body;15 16 // Access cookies17 const sessionToken = request.cookies.get('session_token');18 19 // Set response cookies20 const response = NextResponse.json({ received: { email, name } });21 response.cookies.set('request_id', Date.now().toString(), {22 httpOnly: true,23 secure: process.env.NODE_ENV === 'production',24 sameSite: 'strict'25 });26 27 return response;28}Building RESTful API Patterns
1// app/api/posts/route.ts2import { NextRequest, NextResponse } from 'next/server';3 4// GET /api/posts - List all posts with pagination5export async function GET(request: NextRequest) {6 const { searchParams } = request.nextUrl;7 const page = parseInt(searchParams.get('page') || '1');8 const limit = parseInt(searchParams.get('limit') || '10');9 10 const posts = await fetchPosts({ page, limit });11 const total = await countPosts();12 13 return NextResponse.json({14 data: posts,15 pagination: {16 page,17 limit,18 total,19 totalPages: Math.ceil(total / limit)20 }21 });22}23 24// POST /api/posts - Create a new post25export async function POST(request: NextRequest) {26 const body = await request.json();27 28 if (!body.title || !body.content) {29 return NextResponse.json(30 { error: 'Title and content are required' },31 { status: 400 }32 );33 }34 35 const post = await createPost(body);36 return NextResponse.json(post, { status: 201 });37}Security Best Practices
1import { NextRequest, NextResponse } from 'next/server';2import { verifyToken } from '@/lib/auth';3import { validatePost } from '@/lib/validation';4 5export async function POST(request: NextRequest) {6 // Authentication check7 const authHeader = request.headers.get('authorization');8 const token = authHeader?.replace('Bearer ', '');9 10 if (!token) {11 return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });12 }13 14 const user = await verifyToken(token);15 if (!user) {16 return NextResponse.json({ error: 'Invalid token' }, { status: 401 });17 }18 19 // Input validation20 const body = await request.json();21 const validation = validatePost(body);22 23 if (!validation.isValid) {24 return NextResponse.json(25 { error: 'Validation failed', details: validation.errors },26 { status: 400 }27 );28 }29 30 // Authorization check31 if (!user.canCreatePosts) {32 return NextResponse.json({ error: 'Forbidden' }, { status: 403 });33 }34 35 const post = await createPost({ ...body, authorId: user.id });36 return NextResponse.json(post, { status: 201 });37}Performance and Optimization
Advanced Patterns and Use Cases
1// CSV file generation endpoint2import { NextRequest, NextResponse } from 'next/server';3 4export async function GET(request: NextRequest) {5 const { searchParams } = request.nextUrl;6 const format = searchParams.get('format') || 'csv';7 8 const data = await exportData();9 10 if (format === 'csv') {11 const csv = convertToCSV(data);12 return new NextResponse(csv, {13 headers: {14 'Content-Type': 'text/csv',15 'Content-Disposition': `attachment; filename="export-${Date.now()}.csv"`16 }17 });18 }19 20 return NextResponse.json({ data, format: 'json' });21}22 23// Webhook handler with signature verification24import { createHmac } from 'crypto';25 26export async function POST(request: NextRequest) {27 const body = await request.text();28 const signature = request.headers.get('x-webhook-signature');29 const secret = process.env.WEBHOOK_SECRET;30 31 const expectedSignature = createHmac('sha256', secret)32 .update(body)33 .digest('hex');34 35 if (signature !== expectedSignature) {36 return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });37 }38 39 const event = JSON.parse(body);40 await processWebhookEvent(event);41 42 return NextResponse.json({ received: true });43}