Exploring REST API Architecture
When building APIs to handle HTTP messages we’re faced with decisions about URL route structures, request methods, headers, payloads, status codes, safe and idempotent behavior, and more. Which if any of these are REST principles? In this post we’ll look at the initial REST architecture proposed by it’s inventor, Roy Fielding, including resources, representations, and examples.
REST Constraints #
Fielding outlines REST as an architectural style for distributed applications with 6 constraints[1].
Client-server architecture - The most straightforward constraint, the client-server model makes clients, e.g. browsers and crawlers, separate from data storage. Clients make requests to servers and receive responses.
Caching - Responses are labeled as cacheable or non-cacheable and caching is restricted to the client or an intermediary between the server. This is referred as client-cache-stateless-server.
Layered System - A set of hierarchical layers restricts components to interact only with the adjacent layer. For example, a 4-tier architecture has the client layer, web server layer, API layer with caching, and data layer. Each of these interact with their adjacent layers. Intermediaries can include load balancers, proxies, and security.
-
Uniform Interface - A central feature of REST is a set of interfaces between clients and servers. These 4 interfaces listed include resources, representations, request and response messages, and hypermedia, which we’ll cover soon.
- Resource identification
- Representations manipulate resources
- Self-descriptive request and response messages
- Hypermedia as the engine of application state
- Stateless - The server is stateless as each request contains all data necessary for the server to fulfill it, rather than one request split and managed on the server across multiple partial requests. Session state is kept entirely on the client.
- Code-On-Demand - An optional and often unnecessary constraint. Clients can download and execute code in the form of scripts.
Advantages #
We can see some advantages.
- Flexibility - Client/server design with uniform interfaces allow clients and servers to have different implementations and develop independently. A layered system enables intermediaries e.g. proxies, gateways, and firewalls without changing interfaces. Hypermedia-as-the-engine-of-application-state allows clients to decouple from servers. Stateless server enables intermediaries to view requests in isolation, which may be necessary when services are dynamically rearranged.
- Performance - Caching can significantly improve performance, especially when a layered system adds more network requests.
- Scalability - A stateless server model eases horizontal scaling, avoids shared state problems, and simplifies concurrent requests. A layered system allows hardware resources to scale at specific layers.
- Maintainability - Uniform interfaces include messages as self-descriptive and visible to intermediaries which helps for debugging and network tracing.
Fielding wrote REST architecture “ignores details of protocol syntax and component implementation”[1]. REST is an architecture, whereas HTTP is one implementation of the architecture. Each could be built independently.
Resources, URLs, and Representations #
Resources are a central feature to REST, abstractly defined as anything which can be data[1]. Examples are an image file, a POJO, a document, the distance from San Francisco to Tokyo.
URLs #
URLs can map to a single resource e.g. movie/1234
or a,
- collection resource - group of resource members of the same type e.g.
movies/
. - composite resource - group of different resources. e.g. a homepage with various components.
URL paths are named after resource attributes and we can think of them as nouns instead of verbs. Their paths are also structured hierarchically, in order of increasing specificity left to right. Some resource URL examples.
# profile resource
https://twitter.com/SpaceX
# profile photo resource
https://twitter.com/SpaceX/photo
# single tweet resource
https://twitter.com/SpaceX/status/15892
Representations #
Clients perform actions on resources using representations, e.g. to retrieve, create, update, and delete. Abstractly, representations are key-value metadata and bytes that transfer state between clients and servers[1]. This metadata allows decision making about the bytes without parsing them.
A representation is information that reflects a past, current, or desired state of a given resource, in a format that can be readily communicated via the protocol. [RFC-7231].
Additionally, multiple types of representations could be used for a single request. Let’s look at an example.
Using HTTP #
Finally we’ll use HTTP to implement REST.
- Representation metadata = HTTP headers, response code, and status message.
- Representation bytes = HTTP message payload.
We covered resources and representations so request methods in the HTTP spec make more sense.
Method | Description |
---|---|
GET | Retrieve a current representation of the resource. |
POST | Create a new resource using given representation. |
PUT | Overwrite a current resource with given representation. |
PATCH | Partially modify a current resource with given representation. |
DELETE | Remove all current representations of the resource. |
HEAD | Same as GET, but only transfer the status line and header section. |
OPTIONS | Describe the communication options for the resource. |
[RFC7231]
Fielding also introduces media type
in REST. Check out how Accept
and Content-Type
headers relate to payload.
Request
GET /movie/1234 HTTP/1.1
Host: www.moviequotes.com
Accept: application/json
Response
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{
"id": 1234,
"title": "Inception",
"quotes": [
"Dreams feel real while we're in them.
It's only when we wake up that we
realize something was actually
strange.",
"If you're going to perform inception,
you need imagination."
],
...
}
Request
GET /movie/1234 HTTP/1.1
Host: www.moviequotes.com
Accept: text/html
Response
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
<html>
<body>
<input type="hidden" id="id" value="1234"/>
<div class="title">
Inception
</div>
<ul class="quotes">
<li>Dreams feel real while we're in
them. It's only when we wake up that
we realize something was actually
strange.</li>
<li>If you're going to perform
inception, you need imagination.</li>
</ul>
...
</body>
</html>
You see how payload format changed in these GET requests to /movie/1234
? The client used Accept
to request the payload data format, also called media type. The server responded with Content-Type
that states the payload as JSON or HTML. Each of these response payloads and its HTTP headers – are different representations of the same resource.
Using HTTP to Choose a Representation #
Choosing the best representation goes beyond Accept
and Content-Type
when multiple representations are available. In server-driven content negotiation, these 4 HTTP request and 4 response headers are used.
Request Header | Response Header |
Effect | Example Values |
---|---|---|---|
Accept | Content-Type | Media type |
application/json application/javascript text/html text/css application/xml multipart/form-data
|
Accept-Language | Content-Language | Human language |
en-US, fr;q=0.9 en-GB zh
|
Accept-Encoding | Content-Encoding | Compression |
gzip, br compress deflate identity
|
Accept-Charset | Content-Type “charset” parameter |
Character encoding | text/html; charset=utf-8 |
Hypermedia as the engine of application state #
Hypermedia is content with non-sequential links to other content types e.g. pages, text files, PNG and JPEG images, video, and more. In short, the Web. To the user, clicking links on a website makes application state transitions.
Fielding says it’s essential for servers to return representations with links for clients, as servers know best what state transitions and resources are available. Servers provide the engine of state changes e.g. HATEOAS. Fielding wrote,
What needs to be done to make the REST architectural style clear on the notion that hypertext is a constraint? In other words, if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period.
He later explains hypertext as presentation of information and controls such that the information becomes the affordance through which the user (or automaton) obtains choices and selects actions.
As examples see links in these 2 response bodies.
Request
GET /orders/523 HTTP/1.1
Host: www.example.com
Accept: application/hal+json
HAL - Hypertext Application Language
Response
HTTP/1.1 200 OK
Content-Type: application/hal+json; charset=utf-8
{
"_links": {
"self": { "href": "/orders/523" },
"warehouse": { "href": "/warehouse/56" },
"invoice": { "href": "/invoices/873" }
},
"currency": "USD",
"status": "shipped",
"total": 10.20
}
[2]
JSON:API
Request
GET /articles HTTP/1.1
Host: example.com
Accept: application/vnd.api+json
Response
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json; charset=utf-8
{
"links": {
"self": { "href": "/orders/523" },
"warehouse": { "href": "/warehouse/56" },
"invoice": { "href": "/invoices/873" }
},
"data": [
{
"type": "orders",
"id": "1",
"attributes": {
"currency": "USD",
"status": "shipped",
"total": 10.20
}
},
...
]
}
[3]
How RESTful is that API? #
We can check how RESTful is an API from Fielding’s definition with some questions. The client-server constraint is a given.
- Does the API use caching either by shared caches e.g. Redis, or browser caches with HTTP headers? (caching)
- Does the API have a single high-level purpose that contributes to (or able to support) a layered system? (layered system)
- Are resource URL paths labeled as nouns and structured hierarchically, increasing in specificity left to right? (uniform interface)
- If multiple representations of a resource are available, are they selected by HTTP headers e.g.
Content-Type
? (uniform interface) - Is the protocol implemented to it’s specification e.g. HTTP? This includes effective use of request methods like GET, POST, and PATCH. (uniform interface)
- Does the server provide links (hypermedia) to the client traversable from root for application state changes? (uniform interface)
- Are servers stateless between requests with session state stored on the client? (stateless)
In this post we covered Fielding’s initial REST architecture including constraints, resources, and representations. I hope you found something useful.
References #
[1] Fielding, Roy G. Chapter 5 Representational State Transfer (REST)