Separation of Concerns in REST APIs

Are you making the most of HTTP’s built-in features to simplify your RESTful API design and boost its performance?

One of the most important reasons behind the success of the REST architectural style is its simplicity, which it achieves through its seamless integration with HTTP. By pushing as much functionality as possible down into the transport layer, REST allows the application layer to remain as simple as possible. Rather than reinventing or replacing HTTP’s functionalities, REST embraces HTTP’s existing feature set, introducing new semantics only when absolutely necessary. This approach not only simplifies the application logic but also allows REST to benefit from ongoing improvements to HTTP standards and infrastructure “for free.” As HTTP continues to evolve, REST APIs automatically gain these enhancements, enabling developers to focus on their applications rather than the underlying transport.

Given the tight integration between REST and HTTP, it’s not always clear whether certain functionalities should be implemented at the transport layer or the application layer. Striking the right balance between HTTP’s responsibilities and REST’s application-level concerns is essential for designing effective, intuitive APIs that developers love to use.

HTTP / Transport Layer Concerns

As REST's underlying transport protocol, HTTP1 is responsible for a range of concerns that ensure the safe and efficient transfer of data between clients and servers. Pushing these undifferentiated concerns down to the transport layer not only simplifies the application logic -- for both clients and servers -- but also leverages the robustness and maturity of HTTP implementations and infrastructure, leading to more secure, reliable, and maintainable APIs.

Encryption

HTTPS (HTTP over TLS/SSL) ensures that data is encrypted while traveling over the network, protecting sensitive information from unauthorized access and ensuring data integrity during transmission. By handling encryption at the transport layer, APIs can guarantee secure communication without needing to implement custom encryption solutions at the application level.

Authentication

HTTP provides mechanisms such as Basic, Digest, and Bearer token authentication to verify client identities, ensuring that only authorized users can access specific resources. Authentication flows like OAuth and OIDC can also be implemented largely independent of the application layer, offering additional standardized methods for securing APIs.

Caching

HTTP supports caching, allowing clients to store responses and reuse them for subsequent requests. This reduces server load and improves response times. By managing caching at the transport level, APIs can offer efficient data retrieval without the complexity of custom caching mechanisms.

Content Negotiation

Through content negotiation, HTTP allows servers to serve different representations of a resource (e.g., JSON, XML, HTML) based on client preferences. This standardized approach ensures that APIs can flexibly meet the needs of different clients without adding complexity to the application layer.

Redirection

HTTP supports redirection natively, enabling servers to direct clients to retrieve resources from alternative locations—for example, redirecting users from HTTP resources to equivalent HTTPS resources or gracefully handling resource renaming.

REST / Application Layer Concerns

While HTTP handles the transport of data, REST focuses on the application layer, addressing concerns specific to the domain and business logic of the application. These include the following.

Data Modeling

The application layer defines the resources and data models—URLs, request data formats, and response data formats—that are used to interact with the API. This ensures that each API is tailored to its specific domain while relying on HTTP for standardized tasks like content negotiation and serialization.

Business Logic

The application layer defines the business logic that dictates how requests are processed, how responses are generated, and how these interactions affect the persistent state of the service. This logic is central to the API’s purpose, reflecting the rules, workflows, and processes unique to the application’s domain.

Localization & Internationalization

REST APIs may need to support different languages and formats, ensuring that resources can be adapted to meet the needs of users from various locales and cultural contexts. By focusing on these aspects within the application layer, REST ensures that the service can be tailored to specific linguistic and cultural needs, while the transport layer manages the mechanics of data exchange.

Shared Concerns / Transport and Application

Request Semantics

HTTP defines2 request methods like GET, POST, PUT, DELETE, and PATCH, which act as the API's "verbs". RESTful applications then define resources (i.e., URL paths) combined with request and response data types, which comprise the API's "nouns". Combining them to create a clear, consistent interface is an exercise in art and science that perforce combines the two layers.

Error Modeling

HTTP provides3 response status codes to represent specific success and failure outcomes: 2xx status codes for success, 4xx status codes for client errors, and 5xx status codes for server errors, among others. However, the semantics of these error codes are coarse-grained and application-independent, so defining detailed failure responses with more in-depth information about the nature of errors, for example using problem+json, is important to API user experience. Much like with request semantics, creating error responses that are useful and standards-compliant without revealing secrets is as much art as it is science.

Flexible Concerns / Transport or Application

Rate Limiting & Request Throttling

HTTP offers limited guidance on rate limiting, aside from the 429 Too Many Requests status code. However, modern HTTP infrastructure, such as load balancers and API gateways, makes it easy to limit call frequency based on the time domain without involving the application layer. However, the application layer may need to get involved to enable rate limiting based on other factors, such as CPU usage or filter count.

Control Flow

Enumerating control flow options, for example determining if there is a next page during pagination, is typically an application-level concern. However, control flow signals can be encoded in the transport layer via HTTP headers4 (e.g., using the Link header for pagination) or the application layer via response entities (e.g., using a next_page response field). Both approaches are effective and valid.

Navigation

The REST concept of HATEOAS involves using links embedded in responses to indicate how different resources relate to each other. Like control flow, this can be managed at the transport layer, the application layer, or a mix of both. Again, both approaches are valid.

One Size Does Not Fit All

While the above division of labor has consistently proven effective, it’s important to recognize that every application is different. This separation of concerns between HTTP and REST should provide a solid foundation, but there are times when these boundaries between layers may blur. For example, some APIs might need to handle caching within the application layer, or they may choose to rely solely on HTTP status codes for error handling, foregoing a more detailed error model.

These practices are guidelines, not hard-and-fast rules. Developers should feel empowered to do what’s right for their specific applications, adapting and evolving their approach as needed to meet the unique demands of their projects.

By understanding the distinct yet complementary roles of HTTP and REST, developers can create APIs that are both robust and flexible, capable of evolving alongside the technologies they are built on.

Footnotes

1 This discussion defines HTTP as the content of RFC 9110, plus content from other well-adopted RFCs, namely 5789 and 6585.

2 The full set of (currently 39) standard HTTP methods is maintained in the IANA HTTP Method Registry. Of course, API designers are free to define their own custom HTTP methods, although this can create compatibility issues.

3 The full set of (currently 43) standard HTTP methods is maintained in the IANA HTTP Status Code Registry. Of course, API designers are free to define their own custom HTTP status codes, although this can create compatibility issues.

4 The full set of (currently 216) standard HTTP headers is maintained in the IANA HTTP Fields Registry. Of course, API designers are free to define their own custom HTTP headers, and this is common practice. It is customary to prefix custom headers with x-, as in x-custom-header.

More blog posts

see all