API Design Guidelines
This document outlines the recommended guidelines for designing APIs that are consistent, predictable, and easy for developers to integrate with. Following these principles ensures a high-quality developer experience.
1. RESTful Principles
Our APIs are designed following RESTful architectural constraints:
- Client-Server Architecture: Separation of concerns between client and server.
- Statelessness: Each request from a client to the server must contain all the information necessary to understand and complete the request. The server should not store any client context between requests.
- Cacheability: Responses should indicate whether they are cacheable to improve performance.
- Uniform Interface: This is the core of REST. It includes:
- Identification of resources through URIs.
- Manipulation of resources through representations.
- Self-descriptive messages.
- HATEOAS (Hypermedia as the Engine of Application State) where applicable.
- Layered System: Clients cannot tell whether they are connected directly to the end server, or to an intermediary along the way.
- Code on Demand (Optional): Servers can temporarily extend or customize the functionality of a client by transferring executable code.
2. Resource Naming and URIs
Resources should be named using nouns, not verbs, and should follow a hierarchical structure.
- Use plural nouns for collections of resources (e.g.,
/users
, /products
).
- Use specific identifiers for individual resources within a collection (e.g.,
/users/{userId}
, /products/{productId}
).
- Use nested resources for related entities (e.g.,
/users/{userId}/orders
).
- URIs should be lowercase and use hyphens to separate words (e.g.,
/api-guidelines
).
- Avoid overly deep nesting.
3. HTTP Methods
Use standard HTTP methods to perform operations on resources:
- GET: Retrieve a representation of a resource or a collection of resources. Should be safe and idempotent.
- POST: Create a new resource within a collection, or perform an action that doesn't fit other methods. Not idempotent.
- PUT: Update or replace an existing resource entirely. Idempotent.
- PATCH: Partially update an existing resource. Not necessarily idempotent.
- DELETE: Remove a resource. Idempotent.
4. Request and Response Formats
APIs should consistently use JSON for request and response bodies.
- Content-Type: Use
application/json
for all JSON payloads.
- Accept: Clients should specify
Accept: application/json
to indicate their preference.
- Data Structure: Use clear, descriptive keys for JSON objects. Avoid abbreviations.
Example: Fetching User Data
GET /users/123 HTTP/1.1
Host: api.example.com
Accept: application/json
{
"id": "123",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane.doe@example.com",
"registeredAt": "2023-10-27T10:00:00Z"
}
5. Status Codes
Use standard HTTP status codes to indicate the outcome of a request.
- 2xx Success:
200 OK
: Request succeeded.
201 Created
: Resource successfully created.
204 No Content
: Request succeeded, but there's no response body.
- 3xx Redirection: (Less common in typical API interactions)
- 4xx Client Errors:
400 Bad Request
: The request was malformed or invalid.
401 Unauthorized
: Authentication is required and has failed or not been provided.
403 Forbidden
: The authenticated user does not have permission to access the resource.
404 Not Found
: The requested resource could not be found.
405 Method Not Allowed
: The HTTP method used is not supported for this resource.
409 Conflict
: The request could not be completed due to a conflict with the current state of the resource.
422 Unprocessable Entity
: The request is well-formed but contains semantic errors.
- 5xx Server Errors:
500 Internal Server Error
: A generic error occurred on the server.
503 Service Unavailable
: The server is temporarily unable to handle the request.
Tip: Always provide a descriptive error message in the response body for 4xx and 5xx status codes.
{
"error": {
"code": "invalid_input",
"message": "The provided email address is not valid."
}
}
6. Pagination
For collections that may return many items, implement pagination to avoid overwhelming the client and server.
- Use query parameters like
page
, limit
, offset
, or pageSize
.
- Include metadata in the response about pagination, such as total count, next/previous page links.
Example: Paginated Users
GET /users?page=2&limit=50 HTTP/1.1
Host: api.example.com
Accept: application/json
{
"totalCount": 1234,
"pageSize": 50,
"currentPage": 2,
"nextPage": "/users?page=3&limit=50",
"previousPage": "/users?page=1&limit=50",
"data": [
// ... 50 user objects ...
]
}
7. Filtering, Sorting, and Searching
Provide mechanisms for clients to filter, sort, and search collections.
- Use query parameters for these operations (e.g.,
/products?category=electronics&sortBy=price:desc
).
- Document the available filter fields, sortable fields, and search capabilities clearly.
8. Security Considerations
Important: Security is paramount. Always use HTTPS for all API communication.
- Implement robust authentication mechanisms (e.g., OAuth 2.0, API Keys).
- Enforce authorization based on user roles and permissions.
- Validate all incoming data to prevent injection attacks.
- Do not expose sensitive information in URIs or query parameters.
9. Versioning
Plan for API evolution by implementing a clear versioning strategy.
- Common strategies include URI versioning (e.g.,
/v1/users
) or header versioning.
- Clearly document your versioning strategy and provide a migration path for older versions.
10. Documentation and Examples
Comprehensive and up-to-date documentation is crucial for developer adoption.
- Provide clear descriptions of all resources, endpoints, parameters, and response structures.
- Include practical code examples in various popular programming languages.
- Use tools like OpenAPI (Swagger) to generate interactive documentation.
By adhering to these guidelines, we aim to build APIs that are robust, scalable, and a pleasure for developers to work with.