API Design Patterns
RESTful APIs, OpenAPI, error handling, rate limiting, and API versioning.
Overview
Well-designed APIs provide consistent and reliable interfaces.
Key Concepts
- RESTful Design — Resource-based URLs
- OpenAPI/Swagger — API documentation
- Error Handling — Consistent error responses
- Rate Limiting — Prevent abuse
- API Versioning — Maintain backward compatibility
Code Examples
// app/api/v1/users/route.js
import { NextResponse } from 'next/server';
export async function GET(request) {
try {
const users = await db.users.findMany();
return NextResponse.json({ data: users });
} catch (error) {
return NextResponse.json(
{ error: { code: 'INTERNAL_ERROR', message: 'Failed to fetch users' } },
{ status: 500 }
);
}
}
export async function POST(request) {
try {
const body = await request.json();
// Validation
const errors = validateUser(body);
if (errors.length > 0) {
return NextResponse.json(
{ error: { code: 'VALIDATION_ERROR', details: errors } },
{ status: 400 }
);
}
const user = await db.users.create({ data: body });
return NextResponse.json({ data: user }, { status: 201 });
} catch (error) {
return NextResponse.json(
{ error: { code: 'INTERNAL_ERROR', message: 'Failed to create user' } },
{ status: 500 }
);
}
}
// Rate limiting middleware
const rateLimit = new Map();
export function middleware(request) {
const ip = request.ip;
const now = Date.now();
const windowMs = 60 * 1000; // 1 minute
const maxRequests = 100;
if (!rateLimit.has(ip)) {
rateLimit.set(ip, []);
}
const requests = rateLimit.get(ip).filter(timestamp => now - timestamp < windowMs);
requests.push(now);
rateLimit.set(ip, requests);
if (requests.length > maxRequests) {
return NextResponse.json(
{ error: 'Too many requests' },
{ status: 429 }
);
}
return NextResponse.next();
}
Practice
Build a RESTful API with proper error handling and rate limiting.