Table of Contents

Share this post

API Design Principles for Modern Web Applications
API Designยทยท5 min readยท9,143 views

API Design Principles for Modern Web Applications

Best practices for designing RESTful APIs that are intuitive, maintainable, and scalable.

API Design Principles for Modern Web Applications

A well-designed API is a joy to use. A poorly designed one causes frustration and bugs. Here's how to design APIs that developers will love.

RESTful Resource Design

Use Nouns, Not Verbs

โœ… GET /users/123
โœ… POST /users
โœ… PUT /users/123
โœ… DELETE /users/123

โŒ GET /getUser/123
โŒ POST /createUser
โŒ POST /updateUser/123
โŒ POST /deleteUser/123

Nested Resources

GET /users/123/posts        # Get all posts by user 123
GET /users/123/posts/456    # Get post 456 by user 123
POST /users/123/posts       # Create post for user 123

But don't nest too deep:

โŒ /users/123/posts/456/comments/789/likes

โœ… /comments/789/likes

HTTP Methods Correctly

GET - Read Only

GET /users/123
  • Idempotent: Multiple calls return same result
  • No side effects
  • Cacheable

POST - Create

POST /users
Content-Type: application/json

{
  "name": "John Doe",
  "email": "john@example.com"
}

Response: 201 Created
Location: /users/124

PUT - Full Update

PUT /users/123

{
  "name": "John Updated",
  "email": "john.updated@example.com"
}
  • Idempotent
  • Replaces entire resource

PATCH - Partial Update

PATCH /users/123

{
  "name": "John Updated"
}
  • Only updates specified fields
  • More flexible than PUT

DELETE - Remove

DELETE /users/123

Response: 204 No Content

Response Status Codes

Use appropriate status codes:

Success (2xx)

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

Client Errors (4xx)

  • 400 Bad Request: Invalid input
  • 401 Unauthorized: Not authenticated
  • 403 Forbidden: Authenticated but no permission
  • 404 Not Found: Resource doesn't exist
  • 422 Unprocessable Entity: Validation failed

Server Errors (5xx)

  • 500 Internal Server Error: Generic server error
  • 503 Service Unavailable: Service is down

Error Responses

Provide useful error information:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid input data",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address"
      },
      {
        "field": "age",
        "message": "Must be at least 18"
      }
    ]
  }
}

Versioning

Include version in URL:

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

Or use headers:

Accept: application/vnd.myapi.v1+json

Pagination

For list endpoints:

GET /users?page=2&limit=20

Response:
{
  "data": [...],
  "pagination": {
    "total": 150,
    "page": 2,
    "limit": 20,
    "total_pages": 8
  }
}

Or cursor-based:

GET /users?cursor=abc123&limit=20

Response:
{
  "data": [...],
  "pagination": {
    "next_cursor": "xyz789",
    "has_more": true
  }
}

Filtering and Sorting

GET /users?status=active&sort=-created_at&fields=id,name,email
  • Filtering: ?status=active
  • Sorting: ?sort=-created_at (- for descending)
  • Field selection: ?fields=id,name,email

Rate Limiting

Include rate limit headers:

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

Return 429 when exceeded:

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

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "API rate limit exceeded"
  }
}

Authentication

Use JWT tokens:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

HATEOAS (Optional)

Include links to related resources:

{
  "id": 123,
  "name": "John Doe",
  "links": {
    "self": "/users/123",
    "posts": "/users/123/posts",
    "avatar": "/users/123/avatar"
  }
}

Documentation

Always provide:

  • Endpoint descriptions
  • Request/response examples
  • Authentication requirements
  • Rate limits
  • Error codes

Use tools like:

  • Swagger/OpenAPI
  • Postman Collections
  • API Blueprint

Security Best Practices

  1. Always use HTTPS
  2. Validate all input
  3. Use parameterized queries (prevent SQL injection)
  4. Implement rate limiting
  5. Add CORS headers appropriately
  6. Never expose sensitive data in URLs
  7. Use proper authentication

Testing

Test your API:

describe('Users API', () => {
  it('should create a user', async () => {
    const response = await request(app)
      .post('/api/v1/users')
      .send({ name: 'John', email: 'john@example.com' })
      .expect(201);
    
    expect(response.body).toHaveProperty('id');
  });
  
  it('should return validation error', async () => {
    await request(app)
      .post('/api/v1/users')
      .send({ name: 'John' })
      .expect(422);
  });
});

Conclusion

Good API design is about:

  • Consistency
  • Predictability
  • Clear error messages
  • Proper HTTP usage
  • Good documentation

Follow these principles, and your API will be easy to use and maintain.

Comments (0)

Loading comments...