RESTful web services are services built according to REST principles. The idea is to have them designed to essentially work well on the web. But, what is REST? Let's start from the beginning by defining REST.
This article is taken from the book Hands-On RESTful Web Services with TypeScript 3 by Biharck Muniz Araújo. This book is a step-by-step guide that will help you design, develop, scale, and deploy RESTful APIs with TypeScript 3 and Node.js. In this article we will learn what is REST and talk about various REST architectural styles.
The REST (Representational State Transfer) style is a set of software engineering practices that contains constraints that should be used in order to create web services in distributed hypermedia systems. REST is not a tool and neither is it a language; in fact, REST is agnostic of protocols, components, and languages.
It is important to say that REST is an architectural style and not a toolkit. REST provides a set of design rules in order to create stateless services that are shown as resources and, in some cases, sources of specific information such as data and functionality. The identification of each resource is performed by its unique Uniform Resource Identifier (URI). REST describes simple interfaces that transmit data over a standardized interface such as HTTP and HTTPS without any additional messaging layer, such as Simple Object Access Protocol (SOAP).
The consumer will access REST resources via a URI using HTTP methods (this will be explained in more detail later). After the request, it is expected that a representation of the requested resource is returned. The representation of any resource is, in general, a document that reflects the current or intended state of the requested resource.
The REST architectural style describes six constraints. These constraints were originally described by Roy Fielding in his Ph.D. thesis. They include the following:
We will discuss them all minutely in the following subsections.
Uniform interface is a constraint that describes a contract between clients and servers. One of the reasons to create an interface between them is to allow each part to evolve regardless of each other. Once there is a contract aligned with the client and server parts, they can start their works independently because, at the end of the day, the way that they will communicate is firmly based on the interface:
The uniform interface is divided into four main groups, called principles:
Let's talk more about them.
One of the key things when a resource is being modeled is the URI definition. The URI is what defines a resource as unique. This representation is what will be returned for clients. If you decided to perform GET to the offer URI, the resource that returns should be a resource representing an order containing the ID order, creation date, and so on. The representation should be in JSON or XML.
Here is a JSON example:
{ id : 1234, creation-date : "1937-01-01T12:00:27.87+00:20", any-other-json-fields... }
Here is an XML example:
<order> <id>1234</id> <creation-date>1937-01-01T12:00:27.87+00:20</creation-date> any-other-xml-fields </order>
Following the happy path, when the client makes a request to the server, the server responds with a resource that represents the current state of its resource. This resource can be manipulated by the client. The client can request what kind it desires for the representation such as JSON, XML, or plain text.
When the client needs to specify the representation, the HTTP Accept header is used.
Here you can see an example in plain text:
GET https://<HOST>/orders/12345 Accept: text/plain
The next one is in JSON format:
GET https://<HOST>/orders/12345 Accept: application/json
In general, the information provided by the RESTful service contains all the information about the resource that the client should be aware of. There is also a possibility of including more information than the resource itself. This information can be included as a link. In HTTP, it is used as the content-type header and the agreement needs to be bilateral—that is, the requestor needs to state the media type that it's waiting for and the receiver must agree about what the media type refers to.
Some examples of media types are listed in the following table:
Extension | Document Type | MIME type |
.aac | AAC audio file | audio/aac |
.arc | Archive document | application/octet-stream |
.avi | Audio Video Interleave (AVI) | video/x-msvideo |
.css | Cascading Style Sheets (CSS) | text/css |
.csv | Comma-separated values (CSV) | text/csv |
.doc | Microsoft Word | application/msword |
.epub | Electronic publication (EPUB) | application/epub+zip |
.gif | Graphics Interchange Format (GIF) | image/gif |
.html | HyperText Markup Language (HTML) | text/html |
.ico | Icon format | image/x-icon |
.ics | iCalendar format | text/calendar |
.jar | Java Archive (JAR) | application/java-archive |
.jpeg | JPEG images | image/jpeg |
.js | JavaScript (ECMAScript) | application/javascript |
.json | JSON format | application/json |
.mpeg | MPEG video | video/mpeg |
.mpkg | Apple Installer Package | application/vnd.apple.installer+xml |
.odt | OpenDocument text document | application/vnd.oasis.opendocument.text |
.oga | OGG audio | audio/ogg |
.ogv | OGG video | video/ogg |
.ogx | OGG | application/ogg |
.otf | OpenType font | font/otf |
.png | Portable Network Graphics | image/png |
Adobe Portable Document Format (PDF) | application/pdf | |
.ppt | Microsoft PowerPoint | application/vnd.ms-powerpoint |
.rar | RAR archive | application/x-rar-compressed |
.rtf | Rich Text Format (RTF) | application/rtf |
.sh | Bourne shell script | application/x-sh |
.svg | Scalable Vector Graphics (SVG) | image/svg+xml |
.tar | Tape Archive (TAR) | application/x-tar |
.ts | TypeScript file | application/typescript |
.ttf | TrueType Font | font/ttf |
.vsd | Microsoft Visio | application/vnd.visio |
.wav | Waveform Audio Format | audio/x-wav |
.zip | ZIP archive | application/zip |
.7z | 7-zip archive | application/x-7z-compressed |
HATEOAS is a way that the client can interact with the response by navigating within it through the hierarchy in order to get complementary information.
For example, here the client makes a GET call to the order URI :
GET https://<HOST>/orders/1234
The response comes with a navigation link to the items within the 1234 order, as in the following code block:
{ id : 1234, any-other-json-fields..., links": [ { "href": "1234/items", "rel": "items", "type" : "GET" } ] }
What happens here is that the link fields allow the client to navigate until 1234/items in order to see all the items that belong to the 1234 order.
Essentially, stateless means that the necessary state during the request is contained within the request and it is not persisted in any hypothesis that could be recovered further. Basically, the URI is the unique identifier to the destination and the body contains the state or changeable state, or the resource. In other words, after the server handles the request, the state could change and it will send back to the requestor with the appropriate HTTP status code:
In comparison to the default session scope found in a lot of existing systems, the REST client must be the one that is responsible in providing all necessary information to the server, considering that the server should be idempotent.
Stateless allows high scalability since the server will not maintain sessions. Another interesting point to note is that the load balancer does not care about sessions at all in stateless systems.
In other words, the client needs to always pass the whole request in order to get the resource because the server is not allowed to hold any previous request state.
The aim of caching is to never have to generate the same response more than once. The key benefits of using this strategy are an increase in speed and a reduction in server processing.
Essentially, the request flows through a cache or a series of caches, such as local caching, proxy caching, or reverse proxy caching, in front of the service hosting the resource. If any of them match with any criteria during the request (for example, the timestamp or client ID), the data is returned based on the cache layer, and if the caches cannot satisfy the request, the request goes to the server:
The REST style separates clients from a server. In short, whenever it is necessary to replace either the server or client side, things should flow naturally since there is no coupling between them. The client side should not care about data storage and the server side should not care about the interface at all:
Each layer must work independently and interact only with the layers directly connected to it. This strategy allows passing the request without bypassing other layers. For instance, when scaling a service is desired, you might use a proxy working as a load balancer—that way, the incoming requests are deliverable to the appropriate server instance. That being the case, the client side does not need to understand how the server is going to work; it just makes requests to the same URI.
The cache is another example that behaves in another layer, and the client does not need to understand how it works either:
In summary, this optional pattern allows the client to download and execute code from the server on the client side. The constraint says that this strategy improves scalability since the code can execute independently of the server on the client side:
In this post, we discussed various REST architectural styles based on six constraints. To know more about best practices for RESTful design such as API endpoint organization, different ways to expose an API service, how to handle large datasets, check out the book Hands-On RESTful Web Services with TypeScript 3.
7 reasons to choose GraphQL APIs over REST for building your APIs
Which Python framework is best for building RESTful APIs? Django or Flask?