Characteristics
- Client-Server Architecture: REST follows a client-server model where the client and server are independent entities. This allows for the client and server to evolve independently.
- Stateless: Each request from a client to a server must contain all the information needed to understand and process the request. The server does not store any client contexts between requests.
- Cacheability: Responses from the server can be marked as cacheable or non-cacheable, enabling clients to cache responses to improve efficiency and reducing the load on server.
- Layered System: REST APIs are built in a way that allows multiple layers to exist between the client and server, like load balancers, proxies, or gateways to enhance scalability and security, and to hide backend complexity from clients.
- Uniform interface: A consistent interface ensures that all resources and endpoints follow predictable and standardized patterns, making the API more intuitive, maintainable, and user-friendly. This is achieved through standard HTTP methods, consistent resource URIs, consistent naming conventions, etc
4 constraints to validate RESTfullness
- Identification of resources:
- Rule: Every resource (e.g. user, order, product) must be uniquely identifiable via a URI
- Purpose: Enables clients to locate and interact with resources via consistent and clear URIs, simplifying resource retrieval and modification. For example:
- /users/123: URI for a specific user with ID 123
- /products/567: URI for a specific product with ID 567
- Manipulation of resources through representation:
- Rule: Interactions with resources should be done through representations, typically in standard formats like JSON or XML.
- Purpose: When a client retrieves a resource, they receive a representation (e.g. JSON object) of that resource, which can be modified and sent back to the server if updates are needed. This approach decouples data storage from data representation and makes API more flexible.
- Self-Descriptive messages:
- Rule: Each request and response should contain enough information for clients and servers to process the message independently.
- Purpose: This includes using standard HTTP methods (GET, POST, PUT, DELETE) and status codes, which indicate the purpose and outcome of each interaction without relying on prior knowledge of the server's state. Headers, HTTP methods, and response status codes should consistently communicate the intent and result of each request.
- Hypermedia as the Engine of Application State
- Rule: Responses should contain links (hypermedia) that describe the available actions for the client, guiding them on what can be done next with that resource.
- Purpose: Allows clients to dynamically interact with the API based on the links provided in each response, making the system more discoverable and self-explanatory
- A response from /users/123 might include a link to /users/123/orders if the client can access the orders for that user.
URI design
- Use Nouns, not verbs: Use /orders instead of /createOrder or /deleteOrder
- Purpose: Emphasizes that URIs represent entities and concepts within the system, making it clear that actions are performed using HTTP methods
- Hierarchical structure: Arrange URIs in a logical hierarchy to represent relationships between resources. For orders belonging to a user, use /users/{userId}/orders instead of flat URIs like /orders.
- Use plural nouns for resource collections: Use /users for a collection of user resources rather than /user
- Purpose: This rule provides consistency across the API and avoids confusion, as clients will know that /users represents collection, while /users/{id} represents a single resource.
- Avoid trailing slashes: Do not use trailing slashes at the end of URIs, unless specifically required.
- Use lowercase letters: URIs are case-sensitive
- Avoid file extensions: Do not use file extensions like .json or .xml in URIs
- Purpose: Content negotiation should handle response formats through HTTP headers, allowing URIs to stay clean and format-agnostic.
- Use query parameters for filtering, sorting, and pagination: /products?category=electronics&sort=price&limit=10
- Purpose: Keeps URI structure focused on resource identification, while query parameters control how results are returned. Also improves readability and usability.
- Use path parameters for specific resources: Use /users/{userId}/orders/{orderId} to specify an order for a specific user.
- Avoid deep nesting: Limit nesting levels in URIs to avoid overly complex structures.
- Do not include language-specific extensions or implementation-specific path.
- Language-specific extension: /vehicles/suv/q6.jsp
- Implementation-specific path: /servlet/vehicles/suv/q6
- Do not include session ID in URIs