Good API design is crucial for developer experience and system success. Here are best practices for designing RESTful APIs.

1. Use RESTful Conventions

Resource-Based URLs

# Good: Resource-based
GET    /api/users
GET    /api/users/123
POST   /api/users
PUT    /api/users/123
DELETE /api/users/123

# Bad: Action-based
GET    /api/getUsers
POST   /api/createUser
POST   /api/deleteUser

HTTP Methods

  • GET: Retrieve resources
  • POST: Create resources
  • PUT: Update entire resource
  • PATCH: Partial update
  • DELETE: Remove resource

2. Consistent Naming

Use Plural Nouns

# Good
GET /api/users
GET /api/orders
GET /api/products

# Bad
GET /api/user
GET /api/order
GET /api/product

Use kebab-case or camelCase

# Good: Consistent
GET /api/user-profiles
GET /api/orderItems

# Bad: Mixed
GET /api/user_profiles
GET /api/order-items

3. Version Your API

URL Versioning

GET /api/v1/users
GET /api/v2/users

Header Versioning

GET /api/users
Accept: application/vnd.api+json;version=2

4. Use Proper HTTP Status Codes

Success Codes

200 OK          # Successful GET, PUT, PATCH
201 Created     # Successful POST
204 No Content  # Successful DELETE

Client Error Codes

400 Bad Request      # Invalid request
401 Unauthorized     # Authentication required
403 Forbidden        # Not authorized
404 Not Found        # Resource doesn't exist
409 Conflict         # Resource conflict
422 Unprocessable    # Validation errors

Server Error Codes

500 Internal Server Error
502 Bad Gateway
503 Service Unavailable

5. Consistent Response Format

Standard Response Structure

{
  "data": {
    "id": "123",
    "type": "user",
    "attributes": {
      "name": "John Doe",
      "email": "[email protected]"
    }
  },
  "meta": {
    "timestamp": "2025-12-10T10:00:00Z"
  }
}

Error Response Format

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input",
    "details": [
      {
        "field": "email",
        "message": "Invalid email format"
      }
    ]
  }
}

6. Pagination

Cursor-Based Pagination

GET /api/users?cursor=eyJpZCI6IjEyMyJ9&limit=20

Response:
{
  "data": [...],
  "pagination": {
    "cursor": "eyJpZCI6IjE0MyJ9",
    "has_more": true
  }
}

Offset-Based Pagination

GET /api/users?page=1&limit=20

Response:
{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 100,
    "total_pages": 5
  }
}

7. Filtering and Sorting

Filtering

GET /api/users?status=active&role=admin
GET /api/orders?created_after=2024-01-01&created_before=2024-12-31

Sorting

GET /api/users?sort=name,email&order=asc,desc
GET /api/users?sort=-created_at  # Descending

8. Field Selection

Sparse Fieldsets

GET /api/users?fields=id,name,email
GET /api/users/123?fields=id,name
GET /api/users/123?include=orders,profile

9. Rate Limiting

Headers

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1609459200

Response

HTTP/1.1 429 Too Many Requests
Retry-After: 60

10. Authentication and Authorization

Use Standard Methods

# Bearer token
Authorization: Bearer <token>

# API key
X-API-Key: <key>

Return Clear Errors

{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired token"
  }
}

11. Documentation

OpenAPI/Swagger

openapi: 3.0.0
info:
  title: User API
  version: 1.0.0
paths:
  /users:
    get:
      summary: List users
      responses:
        '200':
          description: Success

Interactive Documentation

  • Swagger UI: Visual API documentation
  • Postman: API testing and docs
  • Redoc: Beautiful API docs

12. Error Handling

Consistent Error Format

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "User with ID 123 not found",
    "request_id": "req_abc123"
  }
}

Validation Errors

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "errors": [
      {
        "field": "email",
        "message": "Invalid email format",
        "code": "INVALID_FORMAT"
      }
    ]
  }
}

13. Caching

Cache Headers

Cache-Control: public, max-age=3600
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT

Conditional Requests

GET /api/users/123
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"

# 304 Not Modified if unchanged

14. Security Best Practices

Use HTTPS

Always use HTTPS in production.

Input Validation

// Validate all inputs
const schema = z.object({
  email: z.string().email(),
  age: z.number().min(0).max(120),
});

const result = schema.safeParse(req.body);

Sanitize Output

// Sanitize user input
const sanitized = sanitizeHtml(userInput, {
  allowedTags: [],
  allowedAttributes: {},
});

15. Performance Optimization

Compression

Content-Encoding: gzip

Database Optimization

  • Use indexes
  • Avoid N+1 queries
  • Use pagination
  • Cache frequently accessed data

Response Time

  • Target: < 200ms for simple queries
  • Acceptable: < 1s for complex queries
  • Timeout: Set reasonable timeouts

Tools

API Development

  • Postman: API testing
  • Insomnia: API client
  • HTTPie: Command-line client

Documentation

  • Swagger/OpenAPI: API specification
  • Redoc: Documentation generator
  • Stoplight: API design platform

Testing

  • Jest: Unit testing
  • Supertest: API testing
  • Newman: Postman CLI

Conclusion

Good API design:

  • Follows conventions: RESTful principles
  • Is consistent: Predictable patterns
  • Is documented: Clear documentation
  • Is secure: Authentication and validation
  • Is performant: Fast and efficient

Remember: Your API is a product. Design it with your users (developers) in mind.

Key principles:

  1. Consistency: Same patterns throughout
  2. Simplicity: Easy to understand and use
  3. Documentation: Clear and comprehensive
  4. Versioning: Plan for changes
  5. Performance: Fast and efficient

Happy API designing! ๐Ÿš€