Introduction

Next.js enables you to create API routes inside the app/api/ directory. These endpoints run on the server, allowing you to implement backend logic within your Next.js app. API routes serve as backend interfaces defined in app/api/.../route.ts and are ideal for implementing RESTful APIs, handling webhooks, or serving cross-platform clients (e.g., mobile).

Pros: Accessible by various frontends and adhere to traditional API design.

Cons: The API path (e.g., /api/...) is exposed to the client, which may require extra authentication or CORS handling.

Sometimes you need a public endpoint for external services or multiple frontends; API routes in Next.js (App Router) address this need.

Creating API Routes

Each API route is placed in its own folder under app/api/, with the endpoint code defined in a route.ts file.

Basic Example

// app/api/hello/route.ts
export async function GET() {
  const data = { message: "Hello World" };
  return new Response(JSON.stringify(data), {
    headers: { "Content-Type": "application/json" },
  });
}

export async function POST(req: Request) {
  const body = await req.json();
  // Process 'body' here
  return new Response(JSON.stringify({ received: body }), {
    headers: { "Content-Type": "application/json" },
  });
}

Call these endpoints from client components using the native fetch API. For example:

"use client";

export default function TestApi() {
  async function getData() {
    const response = await fetch("/api/hello");
    const data = await response.json();
    console.log(data);
  }

  return (
    <button onClick={getData}>
      Call API
    </button>
  );
}

Calling API Routes from the Frontend

Use fetch within any client (or even server) component to interact with your API routes.

Fetching Data (GET)

const fetchData = async () => {
  const res = await fetch("/api/hello");
  const data = await res.json();
  console.log(data);
};

Sending Data (POST)

const sendData = async () => {
  const res = await fetch("/api/user", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name: "Alice" }),
  });
  const data = await res.json();
  console.log(data);
};

Middleware & Authentication

You can protect API routes by checking headers, cookies, or tokens before returning a response.

// app/api/protected/route.ts
import { NextRequest, NextResponse } from "next/server";

export async function GET(req: NextRequest) {
  const authHeader = req.headers.get("Authorization");
  if (!authHeader || authHeader !== "Bearer mysecrettoken") {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }
  return NextResponse.json({ message: "Authenticated" });
}