Introduction to REST
REST (Representational State Transfer) is an architectural style for designing networked applications. RESTful APIs use HTTP methods to perform operations on resources, making them stateless, cacheable, and scalable. Understanding REST principles is fundamental for building modern web APIs.
A well-designed REST API follows conventions that make it intuitive for developers to use. This guide covers best practices, common mistakes to avoid, and advanced patterns for building production-ready APIs. For microservices architecture, see our APIs & Microservices documentation.
REST Principles
Stateless
Each request contains all information needed to process it. The server doesn't store client context between requests, enabling horizontal scaling.
Resource-Based
APIs expose resources (nouns) rather than actions (verbs). Resources are identified by URLs and manipulated using HTTP methods.
HTTP Methods
Use standard HTTP methods: GET (retrieve), POST (create), PUT (update/replace), PATCH (partial update), DELETE (remove).
Uniform Interface
Consistent interface simplifies client implementation. Use standard HTTP status codes and content types.
URL Design Best Practices
Use Nouns, Not Verbs
URLs should represent resources, not actions. The HTTP method indicates the action. Use plural nouns for collections.
// Good
GET /api/users
POST /api/users
GET /api/users/123
PUT /api/users/123
DELETE /api/users/123
// Bad
GET /api/getUsers
POST /api/createUser
POST /api/deleteUser
Hierarchical Structure
Represent relationships through URL hierarchy. Nested resources show ownership or relationships.
// Good - Shows user owns posts
GET /api/users/123/posts
POST /api/users/123/posts
// Alternative - Flat structure with query params
GET /api/posts?userId=123
Versioning
Version your APIs to manage changes without breaking clients. Common approaches include URL versioning, header versioning, or query parameters.
// URL versioning (most common)
GET /api/v1/users
GET /api/v2/users
// Header versioning
GET /api/users
Accept: application/vnd.api+json;version=1
// Query parameter
GET /api/users?version=1
HTTP Methods and Status Codes
Proper Method Usage
Use HTTP methods correctly: GET for retrieval (idempotent, safe), POST for creation, PUT for full replacement (idempotent), PATCH for partial updates, DELETE for removal (idempotent).
Idempotent methods (GET, PUT, DELETE) can be safely retried. POST is not idempotent - multiple identical requests may create multiple resources. For security considerations, see our Security & Networking guide.
Status Codes
Use appropriate HTTP status codes to communicate results clearly:
- 2xx Success: 200 (OK), 201 (Created), 204 (No Content)
- 4xx Client Error: 400 (Bad Request), 401 (Unauthorized), 403 (Forbidden), 404 (Not Found), 409 (Conflict), 422 (Unprocessable Entity)
- 5xx Server Error: 500 (Internal Server Error), 503 (Service Unavailable)
Request and Response Design
Request Bodies
Use JSON for request and response bodies. Include Content-Type headers. Validate all inputs and return meaningful error messages for invalid data.
// POST /api/users
Content-Type: application/json
{
"name": "John Doe",
"email": "john@example.com"
}
Response Formatting
Use consistent response structures. Include metadata for pagination, filtering, and sorting. Wrap collections in objects for extensibility.
// Collection response
{
"data": [...],
"pagination": {
"page": 1,
"perPage": 20,
"total": 100
}
}
// Single resource
{
"data": {
"id": 123,
"name": "John Doe"
}
}
Common Pitfalls
1. Ignoring HTTP Semantics
Don't use GET for state-changing operations. Don't use POST for idempotent operations. Respect HTTP method semantics for proper caching and tooling support.
2. Inconsistent Naming
Use consistent naming conventions (camelCase, snake_case, or kebab-case) throughout your API. Don't mix conventions. Choose one and stick to it.
3. Poor Error Handling
Return meaningful error messages with appropriate status codes. Include error details, validation errors, and helpful messages. Don't expose internal implementation details. For security, see our Security Fundamentals guide.
4. Missing Pagination
Always paginate collection endpoints. Large result sets consume resources and slow responses. Implement cursor-based or offset-based pagination with reasonable defaults.
5. Over-fetching and Under-fetching
Allow clients to specify fields they need (field selection). Don't return unnecessary data. Consider GraphQL for complex querying needs. See our APIs & Microservices guide for GraphQL.
Security Best Practices
Authentication
Use OAuth 2.0, JWT tokens, or API keys. Never send credentials in URLs. Use HTTPS for all communications.
Authorization
Implement proper access control. Check permissions for every request. Use role-based access control (RBAC).
Input Validation
Validate all inputs. Sanitize data to prevent injection attacks. Use parameterized queries for database operations.
Rate Limiting
Implement rate limiting to prevent abuse. Return appropriate headers (X-RateLimit-*) and status code 429 when limits are exceeded.
Performance Optimization
Caching
Use HTTP caching headers (Cache-Control, ETag, Last-Modified) for cacheable resources. Implement server-side caching for expensive operations. Use CDNs for static content.
Cache GET requests appropriately. Don't cache POST, PUT, DELETE requests. For database optimization, see our Database Indexing guide.
Compression
Enable gzip or brotli compression for responses. This significantly reduces payload size and improves performance, especially for mobile clients.
Database Optimization
Optimize database queries. Use indexes appropriately. Implement connection pooling. Consider read replicas for scaling reads.
Avoid N+1 query problems. Use eager loading or batch loading. For database design, see our Databases documentation.
Documentation
Comprehensive API documentation is essential. Use OpenAPI/Swagger specifications. Include examples, error responses, authentication requirements, and rate limits. Keep documentation updated with code changes. Provide interactive documentation when possible.