TS
AdvancedAPI Development

Next.js API Route with Error Handling

A robust Next.js API route with comprehensive error handling, validation, and response formatting.

Next.jsAPIError HandlingValidationTypeScript
TypeScript
129 lines
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);
  }
}

Performance

Includes request validation and response caching headers

Best Practices

  • Comprehensive error handling with proper HTTP status codes
  • Input validation with detailed error messages
  • Structured response format
  • Security headers and CORS handling
February 20, 2024