Advanced Tutorial

API Development

Build robust, scalable APIs with Next.js, authentication, and modern database integration

150 min
Total Duration
Advanced
Difficulty Level
5
Key Modules

Step-by-Step Implementation

Tutorial Sections

1

API Architecture & Design

Learn RESTful principles and design scalable API architecture

1

RESTful API Design Principles

8 min

REST (Representational State Transfer) is an architectural style for designing web services.

Core Principles:
- Stateless: Each request contains all information needed
- Resource-based: URLs represent resources, not actions
- HTTP Methods: Use GET, POST, PUT, DELETE appropriately
- Status Codes: Return meaningful HTTP status codes

Resource Naming:
- Use nouns, not verbs: `/users` not `/getUsers`
- Use plural nouns: `/users` not `/user`
- Hierarchical relationships: `/users/123/posts`
Implementation
// Good API Design Examples

// Users resource
GET    /api/users           // Get all users
GET    /api/users/123       // Get specific user
POST   /api/users           // Create new user
PUT    /api/users/123       // Update user (full)
PATCH  /api/users/123       // Update user (partial)
DELETE /api/users/123       // Delete user

// Nested resources
GET    /api/users/123/posts      // Get user's posts
POST   /api/users/123/posts      // Create post for user
GET    /api/posts/456/comments   // Get post comments

// Query parameters for filtering, sorting, pagination
GET /api/users?page=2&limit=10&sort=name&filter=active

// Response structure
{
  "data": [...],
  "meta": {
    "total": 100,
    "page": 2,
    "limit": 10,
    "totalPages": 10
  },
  "links": {
    "first": "/api/users?page=1",
    "prev": "/api/users?page=1", 
    "next": "/api/users?page=3",
    "last": "/api/users?page=10"
  }
}
2

API Versioning Strategies

7 min

Why Version APIs?
- Maintain backward compatibility
- Allow gradual migration
- Support multiple client versions

Versioning Methods:
1. URL Versioning: `/api/v1/users`
2. Header Versioning: `Accept: application/vnd.api.v1+json`
3. Query Parameter: `/api/users?version=1`

Best Practice: URL versioning is most common and clear.
Implementation
// API Versioning Structure
/api/v1/users     // Version 1 - Original
/api/v2/users     // Version 2 - Enhanced with new fields
/api/v3/users     // Version 3 - Breaking changes

// Version middleware
// middleware/version.ts
export function apiVersion(req: Request) {
  const url = new URL(req.url);
  const version = url.pathname.split('/')[2]; // Extract v1, v2, etc.
  
  return {
    version: version || 'v1',
    isLatest: version === 'v3'
  };
}

// Handling different versions
export async function GET(request: Request) {
  const { version } = apiVersion(request);
  
  switch (version) {
    case 'v1':
      return getUsersV1();
    case 'v2': 
      return getUsersV2();
    case 'v3':
      return getUsersV3();
    default:
      return getUsersV1(); // Default to v1
  }
}
3

HTTP Status Codes & Error Handling

10 min

Common Status Codes:
- 200 OK: Successful GET, PATCH
- 201 Created: Successful POST
- 204 No Content: Successful DELETE
- 400 Bad Request: Invalid request data
- 401 Unauthorized: Authentication required
- 403 Forbidden: Access denied
- 404 Not Found: Resource doesn't exist
- 422 Unprocessable Entity: Validation errors
- 500 Internal Server Error: Server error

Error Response Format:
Consistent error structure helps clients handle errors properly.
Implementation
// Error response types
interface ApiError {
  error: {
    code: string;
    message: string;
    details?: any;
    timestamp: string;
  };
}

// Error handling utility
export class ApiError extends Error {
  constructor(
    public statusCode: number,
    public code: string,
    message: string,
    public details?: any
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

// Error response helper
export function errorResponse(error: ApiError): Response {
  return Response.json(
    {
      error: {
        code: error.code,
        message: error.message,
        details: error.details,
        timestamp: new Date().toISOString(),
      }
    },
    { status: error.statusCode }
  );
}

// Usage in route handlers
export async function POST(request: Request) {
  try {
    const data = await request.json();
    
    // Validation
    if (!data.email) {
      throw new ApiError(400, 'MISSING_EMAIL', 'Email is required');
    }
    
    if (!isValidEmail(data.email)) {
      throw new ApiError(422, 'INVALID_EMAIL', 'Email format is invalid');
    }
    
    const user = await createUser(data);
    
    return Response.json(user, { status: 201 });
  } catch (error) {
    if (error instanceof ApiError) {
      return errorResponse(error);
    }
    
    // Unexpected errors
    return errorResponse(
      new ApiError(500, 'INTERNAL_ERROR', 'Something went wrong')
    );
  }
}
Section 1 of 2

Ready to Build APIs?

Start creating robust, scalable APIs today