DocsSection 7
7Section 7 of 10

API Design Patterns

API Design Patterns

7.1 RESTful Structure

GET    /api/clients           # List clients
GET    /api/clients/:id       # Get one client
POST   /api/clients           # Create client
PATCH  /api/clients/:id       # Update client
DELETE /api/clients/:id       # Delete client

7.2 Route Handler Pattern

File: app/api/clients/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { withAuth } from '@/app/api/lib/middleware';
import { ClientQueries } from '@/lib/db';

// GET /api/clients
export async function GET(request: NextRequest) {
  return withAuth(request, async (user) => {
    try {
      const clients = await ClientQueries.list({
        limit: 50,
        offset: 0,
      });
      
      return NextResponse.json({ clients });
    } catch (error) {
      console.error('Failed to fetch clients:', error);
      return NextResponse.json(
        { error: 'Failed to fetch clients' },
        { status: 500 }
      );
    }
  });
}

// POST /api/clients
export async function POST(request: NextRequest) {
  return withAuth(request, async (user) => {
    try {
      const body = await request.json();
      
      // Validation
      if (!body.email || !body.name) {
        return NextResponse.json(
          { error: 'Email and name required' },
          { status: 400 }
        );
      }
      
      const client = await ClientQueries.create(body);
      
      return NextResponse.json({ client }, { status: 201 });
    } catch (error) {
      console.error('Failed to create client:', error);
      return NextResponse.json(
        { error: 'Failed to create client' },
        { status: 500 }
      );
    }
  });
}

7.3 Middleware Wrapper Pattern

File: app/api/lib/middleware.ts

export async function withAuth(
  request: NextRequest,
  handler: (user: User) => Promise<NextResponse>
) {
  const user = await getCurrentUser(request);
  
  if (!user) {
    return NextResponse.json(
      { error: 'Unauthorized' },
      { status: 401 }
    );
  }
  
  return handler(user);
}

export async function withAdminAuth(
  request: NextRequest,
  handler: (user: User) => Promise<NextResponse>
) {
  const user = await getCurrentUser(request);
  
  if (!user || user.role !== 'admin') {
    return NextResponse.json(
      { error: 'Forbidden' },
      { status: 403 }
    );
  }
  
  return handler(user);
}