A mobile app or a third-party service might need an API to pull your data. Route Handlers let you write HTTP endpoints right inside your Next.js app. That said, a Server Component reading your own database doesn't need to call your own API — it's simpler to just use the data layer directly.
The mental model
In app/api/notes/route.ts, export functions named after HTTP methods — GET, POST, PUT, PATCH, DELETE. The request body is untrusted input, so you need to validate its shape and length. Return a status code that matches the error — 400, 401, 404, 500. And don't treat filesystem or memory storage inside a Route Handler as durable — it isn't shared across serverless instances.
Let's build it together
// app/api/notes/route.ts
import { NextResponse } from "next/server";
export async function GET() {
const notes = await db.note.findMany();
return NextResponse.json(notes);
}
export async function POST(request: Request) {
const body = await request.json();
if (typeof body.title !== "string" || body.title.trim().length < 3) {
return NextResponse.json({ error: "Title မမှန်ပါ" }, { status: 400 });
}
const note = await db.note.create({ data: { title: body.title.trim() } });
return NextResponse.json(note, { status: 201 });
}How the code works
GET returns the notes list as JSON. POST checks the title in the body — returning 400 if it's invalid, or creating the note and returning 201 if it's valid.
GET /api/notes returns a list, and a valid POST returns 201 with the new note.5-Minute Try-It
Write a DELETE handler in app/api/notes/[id]/route.ts that returns 404 when the id isn't found.
Next.js — Route Handlers — Next.js