REST (Representational State Transfer) is an architectural style for distributed hypermedia systems first introduced in Roy Fielding’s 2000 doctoral dissertation “Architectural Styles and the Design of Network-based Software Architectures” at UC Irvine. Fielding, one of the principal authors of the HTTP protocol, analyzed the success factors of the web and systematized them into architectural principles. REST has become the de facto standard for modern web API design and is widely used for communication between various distributed systems including microservice architectures, mobile applications, and Single Page Applications (SPAs).
What is REST?
REST (Representational State Transfer) is a network-based software architectural style that identifies resources via URIs and transfers state through HTTP methods. “Representational” refers to resource representations (JSON, XML, etc.), while “State Transfer” refers to the transfer of resource state between client and server.
History and Background of REST
Evolution of Web Services
Before REST emerged, web services primarily used SOAP (Simple Object Access Protocol) and XML-RPC. These protocols required complex XML-based message formats, strict type systems, and service definitions through WSDL (Web Services Description Language), making implementation and maintenance difficult. SOAP had advantages in enterprise environments, supporting transactions, security, and message reliability, but had overhead of using complex XML envelopes even for simple data queries.
Roy Fielding’s Contribution
Roy Fielding was a principal author of the HTTP/1.0 and HTTP/1.1 specifications and co-founder of the Apache HTTP Server project, possessing deep understanding of web architecture. In his doctoral dissertation, he analyzed why the web succeeded and systematized these findings into the architectural style called REST. REST was designed to maximally leverage existing web infrastructure (HTTP, URI, caches, proxies) while building simple and scalable systems.
Spread of REST APIs
REST began to be widely adopted from the mid-2000s. When Flickr (2004), Amazon Web Services (2006), and Twitter (2006) released REST APIs, it became the standard for web APIs. Along with the rise of JSON format, REST became an attractive alternative for developers wanting to avoid SOAP’s complexity, and its popularity grew further with the emergence of Ajax and mobile apps.
The 6 Constraints of REST
REST is an architectural style, not a specific protocol or technology. Systems that follow these 6 constraints are considered RESTful.
1. Client-Server
A constraint that separates concerns between clients and servers, enabling independent evolution. Servers handle data storage and business logic while clients handle user interfaces, allowing each to be developed, deployed, and scaled independently.
Benefits of Separation of Concerns
Client-server separation improves scalability through server simplification, enables various clients (web, mobile, IoT) to use the same server API, and allows independent evolution of each component.
2. Stateless
A constraint where each request is independent and servers must not store client session state. All information needed for a request (authentication tokens, context data) must be included in the request itself.
GET /api/users/me HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Accept: application/json
Advantages of Statelessness:
- Scalability: Horizontal scaling is easy since servers don’t maintain sessions
- Reliability: Other servers can handle requests during server failures
- Simplicity: Server implementation becomes simpler and resource efficiency improves
Disadvantages of Statelessness:
- Request size increases as authentication information must be included with every request
- Client-side state management responsibility increases
3. Cacheable
Responses must explicitly indicate whether they are cacheable. Cacheable responses can be reused by clients or intermediate caches (CDN, proxies), reducing server load and shortening response times.
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=3600, must-revalidate
ETag: "a1b2c3d4e5f6"
Last-Modified: Sat, 20 Jul 2024 10:00:00 GMT
{"id": 123, "name": "John Doe", "email": "[email protected]"}
Cache-Related Headers:
| Header | Description | Example |
|---|---|---|
| Cache-Control | Specifies caching policy | max-age=3600, private |
| ETag | Resource version identifier | "a1b2c3d4e5f6" |
| Last-Modified | Last modification time | Sat, 20 Jul 2024 10:00:00 GMT |
| Expires | Cache expiration time (legacy) | Sun, 21 Jul 2024 10:00:00 GMT |
4. Layered System
A constraint where clients only need to know about the immediately adjacent layer and need not know the system structure beyond it. Adding intermediate layers like API Gateway, load balancers, cache servers, and CDN can improve system scalability, security, and performance.
[Client] → [CDN] → [Load Balancer] → [API Gateway] → [Microservices]
Benefits of Layering:
- Security: Place firewalls, authentication servers in intermediate layers
- Scalability: Horizontal scaling through load balancers
- Performance: Shortened response time through CDN and cache servers
- Flexibility: Internal structure can change without affecting clients
5. Uniform Interface
REST’s most important constraint that simplifies system architecture through consistent interfaces and reduces coupling between client and server.
4 Elements of Uniform Interface
- Resource Identification: Uniquely identify resources through URIs
- Resource Manipulation Through Representations: Transfer resource state through representations like JSON, XML
- Self-Descriptive Messages: Messages contain information about how to process them
- HATEOAS: Responses include hyperlinks to possible next actions
6. Code on Demand (Optional)
An optional constraint where servers can transfer executable code (JavaScript, etc.) to clients to dynamically extend client functionality. Web browsers downloading and executing JavaScript is a typical example. This is REST’s only optional constraint.
Richardson Maturity Model
Leonard Richardson presented a model classifying REST API maturity into 4 levels at the 2008 QCon conference. This model is widely used as a criterion for evaluating how RESTful an API is.
| Level | Name | Characteristics | Example |
|---|---|---|---|
| Level 0 | The Swamp of POX | Single URI, single HTTP method (mainly POST) | SOAP, XML-RPC |
| Level 1 | Resources | URIs assigned to individual resources, single method | All operations POST to /users/123 |
| Level 2 | HTTP Verbs | Proper use of HTTP methods and status codes | Distinguishing GET, POST, PUT, DELETE |
| Level 3 | Hypermedia Controls | HATEOAS implementation, links in responses | Related resource links in _links field |
RESTful API vs REST-like API
RESTful API means an API that fully complies with all REST constraints including HATEOAS, while REST-like API means an API that uses HTTP methods and resource-based URLs but doesn’t comply with some constraints like HATEOAS. In reality, most APIs are REST-like APIs at Richardson Maturity Model Level 2, and implementing complete RESTful APIs at Level 3 is rare.
REST API Design Principles
1. Resource-Centric URL Design
REST API URLs should represent resources, not actions. Use nouns and prefer plurals.
Good Examples:
GET /users # List users
GET /users/123 # Get specific user
POST /users # Create new user
PUT /users/123 # Update entire user info
PATCH /users/123 # Partial user info update
DELETE /users/123 # Delete user
Bad Examples:
GET /getUsers
POST /createUser
POST /deleteUser?id=123
GET /user/123/get
Hierarchical Resource Representation:
GET /users/123/posts # User 123's post list
GET /users/123/posts/456 # User 123's post 456
GET /users/123/posts/456/comments # Post 456's comment list
URL Design Rules:
- Use lowercase
- Use hyphens (-) for word separation (avoid underscores)
- Don’t include file extensions
- Don’t include trailing slashes (/)
- Avoid nesting more than 3 levels
2. Proper Use of HTTP Methods
Each HTTP method has unique semantics. Understand and properly use safe and idempotent properties.
| Method | Purpose | Safe | Idempotent | Request Body | Response Body |
|---|---|---|---|---|---|
| GET | Retrieve resources | O | O | X | O |
| POST | Create resources | X | X | O | O |
| PUT | Update entire resource | X | O | O | O |
| PATCH | Partial resource update | X | X | O | O |
| DELETE | Delete resources | X | O | X | X/O |
| HEAD | Retrieve headers only | O | O | X | X |
| OPTIONS | Query supported methods | O | O | X | O |
Safety and Idempotency
Safe: Requests don’t change server state (GET, HEAD, OPTIONS) Idempotent: Same result when executing the same request multiple times (GET, PUT, DELETE)
3. Proper Use of HTTP Status Codes
Clearly communicate request processing results through HTTP status codes.
Success Responses (2xx):
| Code | Meaning | Use Case |
|---|---|---|
| 200 OK | Success | GET, PUT, PATCH success |
| 201 Created | Creation success | Resource created via POST (Location header required) |
| 204 No Content | Success, no body | DELETE success, PUT update only |
| 206 Partial Content | Partial content | Range request processing |
Client Errors (4xx):
| Code | Meaning | Use Case |
|---|---|---|
| 400 Bad Request | Invalid request | Request syntax error, invalid data |
| 401 Unauthorized | Authentication needed | Missing or invalid credentials |
| 403 Forbidden | No permission | Authenticated but insufficient permissions |
| 404 Not Found | Resource not found | Non-existent resource |
| 409 Conflict | Conflict | Resource state conflict |
| 422 Unprocessable Entity | Cannot process | Syntax correct, semantic error |
| 429 Too Many Requests | Limit exceeded | Rate limiting |
Server Errors (5xx):
| Code | Meaning | Use Case |
|---|---|---|
| 500 Internal Server Error | Server error | Unexpected server error |
| 502 Bad Gateway | Gateway error | Upstream server response error |
| 503 Service Unavailable | Service unavailable | Server overload, maintenance |
| 504 Gateway Timeout | Gateway timeout | Upstream response timeout |
4. Versioning Strategies
APIs may change over time, so versioning strategies are needed to add new features while maintaining backward compatibility.
URL Path Versioning:
GET /api/v1/users
GET /api/v2/users
Pros: Clear, intuitive, easy browser testing, simple caching Cons: URLs get longer, REST principle debate (URIs should identify resources)
Header Versioning:
GET /api/users HTTP/1.1
Accept: application/vnd.myapp.v1+json
Pros: Clean URLs, aligns with REST principles, uses content negotiation Cons: Difficult browser testing, complex caching configuration
Query Parameter Versioning:
GET /api/users?version=1
Pros: Simple implementation, easy browser testing Cons: Version may appear optional, complex caching
Practical Recommendation: URL path versioning is most widely used and adopted by most major APIs (Google, Facebook, Twitter).
5. Pagination Strategies
When returning large amounts of data, limit response size through pagination.
Offset-Based Pagination:
GET /api/users?page=2&per_page=20
GET /api/users?offset=20&limit=20
Cursor-Based Pagination:
GET /api/users?cursor=eyJpZCI6MTAwfQ==&limit=20
| Method | Pros | Cons | Suitable For |
|---|---|---|---|
| Offset-based | Simple implementation, can jump to specific pages | Performance degradation with large data, duplicates/omissions on data changes | Small datasets, page numbers needed |
| Cursor-based | Consistent performance with large data, stable with real-time data | Cannot jump to specific pages, complex implementation | Large datasets, infinite scroll, real-time feeds |
Pagination Response Example:
{
"data": [...],
"pagination": {
"total": 1000,
"page": 2,
"per_page": 20,
"total_pages": 50,
"next_cursor": "eyJpZCI6MTIwfQ=="
},
"_links": {
"self": "/api/users?page=2",
"next": "/api/users?page=3",
"prev": "/api/users?page=1",
"first": "/api/users?page=1",
"last": "/api/users?page=50"
}
}
6. Filtering, Sorting, and Searching
Provide filtering, sorting, and search functionality through query parameters.
Filtering:
GET /api/users?status=active&role=admin
GET /api/posts?created_after=2024-01-01&tag=javascript
Sorting:
GET /api/users?sort=created_at # Ascending
GET /api/users?sort=-created_at # Descending (- prefix)
GET /api/users?sort=name,-created_at # Multiple sorts
Searching:
GET /api/users?q=john
GET /api/posts?search=REST+API
Field Selection (Sparse Fieldsets):
GET /api/users?fields=id,name,email
GET /api/posts?fields[posts]=title,content&fields[author]=name
7. HATEOAS (Hypermedia as the Engine of Application State)
A core REST principle that includes links to related resources in responses, enabling clients to discover possible next actions.
{
"id": 123,
"name": "John Doe",
"email": "[email protected]",
"status": "active",
"_links": {
"self": {"href": "/api/users/123"},
"posts": {"href": "/api/users/123/posts"},
"deactivate": {"href": "/api/users/123/deactivate", "method": "POST"},
"delete": {"href": "/api/users/123", "method": "DELETE"}
}
}
Benefits of HATEOAS
Since clients follow response links rather than hardcoded URLs, servers can change URL structures without modifying clients. However, implementation complexity increases and most clients don’t utilize this, so it’s optionally implemented in practice.
8. Error Handling
Use consistent error response formats to improve developer experience.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{
"field": "email",
"message": "Invalid email format",
"code": "INVALID_FORMAT"
},
{
"field": "age",
"message": "Age must be positive",
"code": "INVALID_VALUE"
}
],
"timestamp": "2024-07-20T16:23:17Z",
"path": "/api/users",
"request_id": "req_abc123"
}
}
Error Response Fields:
code: Error code for programmatic handlingmessage: Human-readable error descriptiondetails: Field-level detailed error informationrequest_id: Unique identifier for log tracing
Security Considerations
Authentication Methods
| Method | Characteristics | Suitable For |
|---|---|---|
| API Key | Simple, included in request header or query | Server-to-server, internal systems |
| Basic Auth | Username:password Base64 encoded | Simple auth, HTTPS required |
| Bearer Token (JWT) | Stateless, self-contained token | General user authentication |
| OAuth 2.0 | Delegated authorization | Third-party app integration, social login |
Rate Limiting
Set request limits to prevent API abuse and protect server resources.
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1721484600
Retry-After: 3600
Content-Type: application/json
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Request limit exceeded. Please try again in 1 hour."
}
}
Rate Limiting Algorithms:
- Token Bucket: Allows burst traffic, complex implementation
- Sliding Window: Accurate limiting, uses Redis
- Fixed Window: Simple implementation, possible bursts at boundaries
CORS (Cross-Origin Resource Sharing)
Configure CORS headers to allow API access from different domains.
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
API Documentation
OpenAPI (Swagger)
OpenAPI Specification is the industry standard for defining REST APIs. It describes APIs in YAML or JSON format and can provide interactive documentation through Swagger UI.
openapi: 3.0.0
info:
title: User API
version: 1.0.0
paths:
/users:
get:
summary: List users
parameters:
- name: page
in: query
schema:
type: integer
default: 1
responses:
'200':
description: Success
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
Documentation Tool Selection:
- Public APIs: OpenAPI/Swagger (standard, rich tool ecosystem)
- Internal APIs: Postman Collections (easy team collaboration)
- Quick Prototyping: API Blueprint (Markdown-based)
Limitations and Alternatives to REST
REST is a versatile and widely adopted architectural style, but it’s not optimal for every situation.
| Technology | Pros | Cons | Suitable For |
|---|---|---|---|
| REST | Simple, standardized, easy caching | Over-fetching, multiple requests needed | General CRUD, public APIs |
| GraphQL | Precise data requests, single endpoint | Complex caching, learning curve | Complex data requirements, mobile apps |
| gRPC | High performance, strong typing, bidirectional streaming | Limited browser support, difficult debugging | Inter-microservice communication |
| WebSocket | Real-time bidirectional communication, low latency | Not stateless, complex load balancing | Chat, real-time notifications, games |
Conclusion
REST API design is a complex process that must consider not just technical decisions but also user experience and business requirements. Understanding REST’s 6 constraints and referencing the Richardson Maturity Model is important, but rather than blindly following them, it’s crucial to understand the trade-offs of each design decision and apply them flexibly according to project characteristics. Targeting practical and consistent REST-like APIs (Level 2) while emphasizing thorough documentation and developer experience is the key to successful API design, rather than implementing perfect RESTful APIs (Level 3).