REST — the New Standard in Web Service Architectures
If you ever wander around the web development community, you might have encountered the term
REST sometime. In this article, let’s demystify the concept and see how this architecture has been getting more and more popular in recent years!
1.1 History and Concept
REST is an acronym for Representational State Transfer, a software architectural style that defines a set of constraints and standards to be adhered to when creating web services first introduced by Roy Fielding in 2000 in his dissertation.
Before the birth of REST, there were no principles on how to design or use an API. Its integration required the use of protocols, such as
SOAP, which were notoriously complex to build, handle, and debug. At that time, exposing your APIs for external usage was not an easy and common thing as it is now due to limitations of available solutions.
This changed in 2000 when the true potential of Web APIs was recognized: a group of experts, led by Roy Fielding, invented REST and changed the API landscape once and for all.
REST was created with the target to set a standard that allows two servers to communicate and exchange data anywhere in the world. This is accomplished with a number of elements, which are fundamental building blocks of REST:
- A set of principles and constraints defining how to communicate and exchange data
- A resource-oriented architecture emphasizing on interface uniformity
- Client - Server architecture, without any state or session preservation, aiming to provide a clear separation of concern
- Use of the HTTP protocol and its methods
Soon after its creation, REST was adopted by technology giants, starting with eBays, Amazon, and Flickr. eBay REST API, an early bird in the field, which was easy to use and had solid documentation, was offered to a selection of partners and instantly demonstrated lucrative potentials. With the new API, its marketplace was no longer limited to only visitors on its website, but extended to any website accessing its API.
Nowadays, writing Facebook statuses, tweeting, or storing data in the Cloud are all made possible by the ability of REST to enable everyone to add a feature to a website in a short time.
1.2. REST Principles
For an interface to be considered RESTful, it needs to satisfy a set of guiding principles and constraints.
- Client — Server architecture
REST follows Client-Server model. The aim of this constraint is the separation of concerns, as separating the user interface concerns (client) from the data storage concerns (server) improves the portability of the user interfaces across multiple platforms. This separation allows both the client and the server to evolve independently as it only requires that the interface stays the same.
Communication between the client and the server must always contain all the information needed to perform the request, making it stateless. Session state is kept entirely in the client and the server does not need to know about it. If access to a resource requires authentication, then the client needs to authenticate itself with every request. This principle makes a request independent of others and can be executed without any context.
The data within a response must be labeled as cacheable or non-cacheable. If a response is cacheable, then a client cache is allowed to reuse that response data for later requests. The client, the server and any intermediary components can all cache resources in order to improve performance and scalability.
- Uniform interface
The interface between components must be uniform, enabling every component to evolve independently. As all components follow the same rule when speaking to others, the overall system architecture is simplified and the visibility of interactions is improved. In order to obtain a uniform interface, multiple architectural constraints are needed to guide the behavior of components: identification of resources, resource representations, self-descriptive messages, and hypermedia as the engine of application state.
- Layered system
Individual components cannot see beyond the immediate layer with which they are interacting. This means that a client need not know whether it’s communicating with the actual server, a proxy, or any other intermediary. If a proxy or load balancer is placed between the client and server, it won’t affect their communications, and there won’t be a need to update the client or server code. This allows components to be independent and thus easily replaceable or extendable, as well as improving the system’s scalability.
- Code on demand (optional)
REST provides code on demand functionality, which means servers can temporarily extend or customize the functionality of a client by transferring or downloading executable code.
1.3 Advantages of REST
Perhaps the most significant benefit of REST is the separation of concern. With REST, user interface and data storage concerns are separated, which enhances the portability of the interface to other types of platforms and allows the different components of the developments to be evolved independently.
In addition, REST brings flexibility and independence to application development. Server and database changes can be done without any effects on other parts, as long as the data from each request remains correct. REST can adapt effortlessly to the platforms being used, meaning you can have a Python, PHP, Java, or Node.js server without a problem, provided that the data exchanged is always in the relevant format, typically JSON.
2. RESTful API
RESTful APIs are APIs that follow the REST principles. Like other APIs, they receive requests and return responses, both with certain consistencies.
A RESTful Web Service request contains several components:
- An Endpoint URL
A RESTful web application defines one or more URL endpoints, which the client would call in order to access or manipulate the server’s resources and data, for example:
https://domain/user/42. An endpoint consists of a domain, port, path, and (optionally) query strings, which can be used to send additional information about the resource we want to interact with.
- HTTP Method
Each endpoint defines one or more methods that can be used to call it, which correspond to application CRUD operations Create, Read, Update, and Delete.
Headers contain additional information about the request (metadata) that can be used to identify context of the request, such as application tokens, cookies, acceptable response formats, etc.
The request body contains data to be transmitted to the server in the form of a JSON-encoded data string. The server can then use these data for its internal operations.
https://domain/users: returns a list of all users
https://domain/users?age=19: returns all users that are 19 years old (specified by query string
https://domain/users/42: create a user with ID 42 using data using the body data
https://domain/users/42: update user ID 42 using data using the body data
https://domain/users/42: delete user with ID 42
There are two noticeable components of a response:
Response payload can be anything: data, HTML, an image, etc. Data responses are typically JSON-encoded, but XML, CSV, simple strings, or any other format can be used. For instance, a GET request to endpoint
https://domain/userswill return a list of users in the form of a JSON-encoded string.
- Status Code
Status codes are used to signal the success / failure of the request and are sent in the response headers. For example,
200 OK is used for successful requests,
201 Created is returned when a data record is created. There are also status code to be returned when an error occurs, such as
400 Bad Request when the client sends an invalid request that triggers an error,
404 Not Found when no records are found or the endpoint does not exist, etc.
For more details on types of status code, refer to this documentation from Mozilla.
3. RESTful API Best Practices
3.1. Consistency across API endpoints
Much of the success and popularity of REST comes from its simplicity and flexibility as developers can design and implement however they prefer; nevertheless, too much of flexibility could lead to inconsistencies and conflicts.
Let’s make this clear with some examples:
As you can see, all three ways are valid options to get a user with ID 42. There is absolutely nothing wrong with any of these choices, but as the complexity of the operations increase, the number of possible endpoint choices rise exponentially. Therefore, the first thing you want to do is to keep your API design consistent across your project, especially when you work with other developers. A set of API endpoints like this would do the job:
3.2. Look before you leap
In order to achieve the consensus I mentioned in section 3.1 when working in a team, before actually coding anything, always design your API specifications (what the endpoint URLs are, which data they receive and return, etc.) and sit down with your teammates to review your design. This will make sure that everyone is on the same page and you can fix any inconsistencies with your teammates’ parts. Good planning leads to good executing.
And, please be a good person and inform others when you modify your design, even a little bit, as it would affect their parts as well. Please.
3.3. Resource-centralized naming convention
If you notice, throughout this article, all of my endpoint URLs are in the form of
.../<a Noun>/... . This noun is the
resource we want to access or manipulate with the request.
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. “today’s weather in Los Angeles”), a collection of other resources, a non-virtual object (e.g. a person), and so on. In other words, any concept that might be the target of an author’s hypertext reference must fit within the definition of a resource. — Roy Fielding’s dissertation
In our examples above, resources are
address. In your endpoint URLs, it’s a good practice to include the resource(s) you are manipulating or fetching with that request and if necessary, how to identify them. For instance, a GET request to
/addresses?user_id=42 will return the address where user with ID 42 is staying. The resource we want is
addresses and we identify it with
3.4. Security and authentication
For large-scale web applications, authentication and authorization is among the most important factors. As one of REST’s main principles is stateless, each and every request must be authenticated and authorized individually. How do we do that?
One of the most common way is to use JWT token. It contains an encrypted string which the server can decrypt to get a user’s identity. This encrypted string is sent in the
Authorization header of every request so that the server can have enough context to verify the request’s validity.
In addition to verifying the user’s identity, we also have to verify whether they have the right to access the resource they are requesting. For example, a user with ID 42 can send a GET request to
/users/42 to fetch their own data, but cannot get another user’s data, ID 43 for example, at
/users/43. As users can send any request they want just by modifying the URLs, we must always perform validation and authorization so that data does not fall into the wrong hands. Always make sure to verify and validate a user’s right and permission before returning any information.
Hope this article gives you some good understanding of REST and RESTful API. In the next one, let’s find out what JWT token is and how it verifies your identity. Until next time!