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);
}