A robust Next.js API route with comprehensive error handling, validation, and response formatting.
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
// Request validation schema
const CreatePostSchema = z.object({
title: z.string().min(1, 'Title is required').max(100, 'Title too long'),
content: z.string().min(10, 'Content must be at least 10 characters'),
tags: z.array(z.string()).optional(),
published: z.boolean().default(false)
});
// Response types
interface ApiResponse<T = any> {
success: boolean;
data?: T;
error?: {
message: string;
code: string;
details?: any;
};
}
// Error handler
function handleError(error: unknown): NextResponse<ApiResponse> {
console.error('API Error:', error);
if (error instanceof z.ZodError) {
return NextResponse.json({
success: false,
error: {
message: 'Validation failed',
code: 'VALIDATION_ERROR',
details: error.errors
}
}, { status: 400 });
}
if (error instanceof Error) {
return NextResponse.json({
success: false,
error: {
message: error.message,
code: 'INTERNAL_ERROR'
}
}, { status: 500 });
}
return NextResponse.json({
success: false,
error: {
message: 'An unexpected error occurred',
code: 'UNKNOWN_ERROR'
}
}, { status: 500 });
}
export async function POST(request: NextRequest) {
try {
// Parse and validate request body
const body = await request.json();
const validatedData = CreatePostSchema.parse(body);
// Simulate database operation
const newPost = {
id: Date.now().toString(),
...validatedData,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
// Return success response
return NextResponse.json({
success: true,
data: newPost
}, {
status: 201,
headers: {
'Cache-Control': 'no-cache',
'Content-Type': 'application/json'
}
});
} catch (error) {
return handleError(error);
}
}
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const page = parseInt(searchParams.get('page') || '1');
const limit = parseInt(searchParams.get('limit') || '10');
// Validate pagination parameters
if (page < 1 || limit < 1 || limit > 100) {
throw new Error('Invalid pagination parameters');
}
// Simulate data fetching
const posts = Array.from({ length: limit }, (_, i) => ({
id: (page - 1) * limit + i + 1,
title: `Post ${(page - 1) * limit + i + 1}`,
content: 'Sample content...',
published: true,
createdAt: new Date().toISOString()
}));
return NextResponse.json({
success: true,
data: {
posts,
pagination: {
page,
limit,
total: 100,
totalPages: Math.ceil(100 / limit)
}
}
}, {
headers: {
'Cache-Control': 'public, max-age=300',
'Content-Type': 'application/json'
}
});
} catch (error) {
return handleError(error);
}
}
Includes request validation and response caching headers
A reusable custom hook that manages Firebase authentication state with loading states and error hand...
A React hook for real-time Firestore data with automatic subscription management and error handling.