Exploring REST API Architecture

When building APIs to handle HTTP messages we often set up URL structures, request methods, headers, payloads, response status codes, safe and idempotent behavior, and more. These HTTP features implement a set of interfaces for one of the most prominent API architectures, called Representational State Transfer or REST. In Postman’s latest State of the API survey, REST is the dominant architectural style used by 93.4% of respondents[1]. So what makes APIs RESTful?

In this post we’ll look at the initial REST architecture introduced in Roy Fielding and cover its constraints, resources, and representations, HTTP examples, and a REST API checklist.

REST Constraints #

Fielding outlines REST as an architectural style for distributed applications with 6 constraints[3].

layers5.png

Advantages #

We can see some advantages.

Fielding wrote REST architecture “ignores details of protocol syntax and component implementation”[3]. 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[3]. 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,

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[3]. 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.

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 the enclosed representation.
PUT Replace all current representations of the resource with the request payload.
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.

movie5.jpg

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 server know next best available resources for users. 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.

Two hypermedia examples.

HAL - Hypertext Application Language #

Request

GET /orders/523 HTTP/1.1
Host: www.example.com
Accept: application/hal+json

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
}

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
      }
    }, 
    ...
  ]
}

The response payloads return hypermedia links with self, warehouse, and invoice links for user to click.


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.



In this post we covered Fielding’s initial REST architecture including constraints, resources, and representations. I hope you found something useful.

References #

[1] Postmans’ 2020 State of the API Survey

[2] Steven Holl, Linked Hybrid, Placesjournal

[3] Fielding, Roy G. Chapter 5 Representational State Transfer (REST)

[4] Inception, image from Subculture Media

[5] JSON Hypertext Application Language

[6] JSON:API A specification for building APIs in JSON

 
10
Kudos
 
10
Kudos

Now read this

Type Checking Techniques in JavaScript Part 2 of 2

To get the most out of this article you’ll want a solid grasp of JavaScript’s data types including built-in, custom, and host objects. If you need a little refresher see Part 1. As front-end developers today are working with larger code... Continue →