ShipNext

Add A Protected API

Create a Route Handler that requires a logged-in user or admin permissions.

API routes do not participate in page i18n and should stay under app/api. The auth module provides getUser, requireUser, and requireAdmin.

Create the API route

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

export async function GET(request: NextRequest) {
  return NextResponse.json({ ok: true });
}

Require a logged-in user

import { type NextRequest, NextResponse } from "next/server";
import { unauthorizedResponse } from "@/core/response/responses";
import { getUser } from "@/modules/auth/server";

export async function GET(request: NextRequest) {
  const user = await getUser(request);
  if (!user) {
    return unauthorizedResponse();
  }

  return NextResponse.json({ userId: user.id });
}

Require admin

import { type NextRequest, NextResponse } from "next/server";
import { ForbiddenError, UnauthorizedError } from "@/core/error/errors";
import {
  forbiddenResponse,
  unauthorizedResponse,
} from "@/core/response/responses";
import { requireAdmin } from "@/modules/auth/server";

export async function POST(request: NextRequest) {
  try {
    const user = await requireAdmin(request);
    return NextResponse.json({ adminId: user.id });
  } catch (error) {
    if (error instanceof UnauthorizedError) return unauthorizedResponse();
    if (error instanceof ForbiddenError) return forbiddenResponse();
    throw error;
  }
}

Keep business logic in modules

Route Handlers should do auth, input parsing, and responses. Put actual business logic in services/repositories such as:

src/modules/billing/services/*
src/modules/storage/repositories/*

Reference existing APIs:

  • app/api/user/profile/route.ts
  • app/api/payment/checkout/route.ts
  • app/api/storage/usage/route.ts

On this page