API Route Handlers (route.ts): Building RESTful Microservices0%
API Route Handlers (route.ts): Building RESTful Microservices
Beginner12 min read•Updated: Jul 11, 2026
API Route Handlers (route.ts): Building RESTful Microservices
While Server Components and Server Actions handle most internal data fetching and mutations, modern full-stack web applications frequently need to expose public RESTful endpoints for third-party integrations, mobile applications, webhooks (e.g., Stripe, Razorpay), or external microservices. Next.js provides Route Handlers via route.ts files.
1. Route Handler Conventions
- Created inside the
app/directory asroute.ts(orroute.js). - Conflict Rule: A
route.tsand apage.tsxCANNOT exist at the same URL segment level! - Handlers export named functions corresponding to standard HTTP verbs:
GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS.
Output
app/
└── api/
├── courses/
│ └── route.ts # GET /api/courses, POST /api/courses
└── webhooks/
└── stripe/
└── route.ts # POST /api/webhooks/stripe
2. Implementing RESTful Handlers: GET & POST
TypeScript
// app/api/courses/route.ts
import { NextRequest, NextResponse } from 'next/server';
import dbConnect from '@/lib/dbConnect';
import Course from '@/models/Course';
// GET: /api/courses?category=web
export async function GET(request: NextRequest) {
await dbConnect();
const searchParams = request.nextUrl.searchParams;
const category = searchParams.get('category');
const filter = category ? { category, isPublished: true } : { isPublished: true };
const courses = await Course.find(filter).lean();
return NextResponse.json({
status: 'success',
results: courses.length,
data: courses
});
}
// POST: /api/courses
export async function POST(request: NextRequest) {
try {
await dbConnect();
const body = await request.json();
if (!body.title || !body.price) {
return NextResponse.json(
{ error: 'Missing required fields: title, price' },
{ status: 400 }
);
}
const newCourse = await Course.create(body);
return NextResponse.json(
{ message: 'Course created successfully', data: newCourse },
{ status: 201 }
);
} catch (error: any) {
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
3. Dynamic Route Handlers with Parameters
TypeScript
// app/api/courses/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server';
import dbConnect from '@/lib/dbConnect';
import Course from '@/models/Course';
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
await dbConnect();
const { id } = await params;
const deleted = await Course.findByIdAndDelete(id);
if (!deleted) {
return NextResponse.json({ error: 'Course not found' }, { status: 404 });
}
return new NextResponse(null, { status: 204 }); // 204 No Content
}
Interactive Quiz
Multiple Choice Questions
Question 1
What special file name is used in the Next.js App Router to create API endpoints?
Question 2
Can a
page.tsx and a route.ts exist within the exact same directory (e.g. app/api/users/)?Question 3
How do you extract query string parameters from an incoming
NextRequest in a Route Handler?Question 4
Which utility is standard in Next.js for sending JSON responses with the correct headers and status codes?
Question 5
Why are Route Handlers ideal for implementing payment provider webhooks (e.g. Stripe, Razorpay)?
Next Lesson
Middleware.ts: Route Protection, Redirects, Cookies & Geolocation
Continue learning with hands-on practice, examples, and exercises in the upcoming topic.
Related Lessons
Practice Quiz
Test your understanding of this lesson with 5 questions. Each question has one correct answer.