Education

Building a Small REST API with Next.js Route Handlers

Intermediate 25 min read VisTechie Team Education
1 views

The basics of a route handler

Any file called route.ts inside app/api can export functions named after HTTP verbs, and Next.js automatically sends the request to whichever one matches.

Step 1 – A GET endpoint

// app/api/posts/route.ts
import { NextResponse } from "next/server";
import { connectDB } from "@/lib/db";
import Post from "@/models/Post";

export async function GET() {
  await connectDB();
  const posts = await Post.find({}).lean();
  return NextResponse.json({ success: true, data: posts });
}

Step 2 – POST, validated with Zod

import { z } from "zod";

const PostSchema = z.object({
  title:   z.string().min(3),
  content: z.string().min(10),
  slug:    z.string().regex(/^[a-z0-9-]+$/),
});

export async function POST(req: Request) {
  const body = await req.json();
  const parsed = PostSchema.safeParse(body);

  if (!parsed.success) {
    return NextResponse.json(
      { success: false, errors: parsed.error.flatten() },
      { status: 422 }
    );
  }

  await connectDB();
  const post = await Post.create(parsed.data);
  return NextResponse.json({ success: true, data: post }, { status: 201 });
}

Step 3 – Don't skip error handling

Wrap your database calls in a try/catch and return something meaningful. A plain 500 with a clear message beats an unhandled rejection taking down your serverless function.

try {
  const post = await Post.create(parsed.data);
  return NextResponse.json({ success: true, data: post }, { status: 201 });
} catch (err) {
  console.error(err);
  return NextResponse.json(
    { success: false, message: "Internal server error" },
    { status: 500 }
  );
}

Putting it together

Typed exports, Zod validation, and consistent error responses - combine those three and you've basically got a template for CRUD endpoints on any resource in your app.

1 views

Comments

0/2000

Comments are reviewed before being published.

Loading comments...

Related Articles