Next.js Lesson 8: API Routes
Next.js lets you write backend API endpoints in the same project as your frontend. No separate server needed.
Route Handlers
// app/api/hello/route.ts
import { NextRequest, NextResponse } from "next/server";
// Handles GET /api/hello
export async function GET(request: NextRequest) {
return NextResponse.json({ message: "Hello from Next.js API!" });
}
// Handles POST /api/hello
export async function POST(request: NextRequest) {
const body = await request.json();
const { name } = body;
return NextResponse.json({ greeting: `Hello, ${name}!` }, { status: 201 });
}
// Also: PUT, PATCH, DELETE, HEAD, OPTIONS
Dynamic API Routes
// app/api/users/[id]/route.ts
export async function GET(
request: NextRequest,
{ params }: { params: { id: string } }
) {
const user = await db.findUser(Number(params.id));
if (!user) return NextResponse.json({ error: "Not found" }, { status: 404 });
return NextResponse.json(user);
}
export async function DELETE(
request: NextRequest,
{ params }: { params: { id: string } }
) {
await db.deleteUser(Number(params.id));
return NextResponse.json({ success: true });
}
Query Params and Headers
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const page = searchParams.get("page") || "1";
const limit = searchParams.get("limit") || "10";
const authHeader = request.headers.get("authorization");
if (!authHeader) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
const data = await fetchPage(Number(page), Number(limit));
return NextResponse.json(data);
}
🏋️ Practice Task
Build a complete /api/tasks CRUD. Use an in-memory array (const tasks = []). GET /api/tasks — list all (support ?done=true filter). POST /api/tasks — create. GET /api/tasks/[id] — get one. PATCH /api/tasks/[id] — toggle done. DELETE /api/tasks/[id] — delete. Test with browser + fetch.
💡 Hint: Route handlers: app/api/tasks/route.ts (GET/POST) and app/api/tasks/[id]/route.ts (GET/PATCH/DELETE).