In this article we will try to explain what is RESTful API and share our experience of working with REST. We will find out what is meant by API, talk about HTTP, learn about REST, see how it works, and describe a simple example of RESTful API architecture design.
A little bit of theory
API (application programming interface) is a set of rules and mechanisms by which one application or component interacts with the others. It seems that the name speaks for itself, but let’s get deeper into details. API can return data that you need for your application in a convenient format (e.g. JSON or XML). In this RESTful API tutorial we will focus on JSON only.
Let’s look at an example. You are probably familiar with the web-application Github. It has its own API, with the help of which you can get information about users, their repositories and much more useful things when developing your app. You can use and manipulate this data in your project.
The example of a standard request to API looks like this:
The request is performed with the help of CURL which is a console utility. There are also browser utilities like Postman, REST Client, etc.
This is what we see in the response:
Now, let’s dwell on REST. This abbreviation stands for representational state transfer. The definition can be conveyed with simpler words: data presentation for a client in the format that is convenient for it. There is one of the main points that you need to understand and remember: REST is not a standard or protocol, this is an approach to or architectural style for writing API.
Closer to REST
A simple definition of RESTful API can easily explain the notion. REST is an architectural style, and RESTful is the interpretation of it. That is, if your back-end server has REST API and you make client-side requests (from a website/application) to this API, then your client is RESTful.
How it works
Work with the server comes down to four essential operations:
- receiving data in a convenient format;
- creating new data;
- updating data;
- deleting data.
REST relies heavily on HTTP. We will not explain the features of this protocol, but it is worth mentioning its great advantage in this situation.
Each operation uses its own HTTP method:
- GET — getting;
- POST — creation;
- PUT — update (modification);
- DELETE — removal.
All these methods (operations) are generally called CRUD. They manage data or as Wikipedia says, “create, read, update and delete” it.
The fact that REST contains a single common interface for requests and databases is its great advantage. This can be viewed in the table below.
All requests you make have their HTTP status codes. There are a lot of them and they are divided into 5 classes. The first number indicates which of them a code belongs to:
- 1xx — informational;
- 2xx — success;
- 3xx — redirection;
- 4xx — client error;
- 5xx — server error.
More details on the list can be found here: List of HTTP status codes.
Today the back end is usually developed not only for web platforms, but also for mobile applications. Therefore, if you create an API without a version and change something on the server, the web will still be updated without problems. But there may be issues with mobile apps. Even if you make changes, there is no guarantee that a user will accept them on their device. You have probably seen how many unconfirmed updates can wait their turn on the phone. So, it is very logical to support both old and new API versions.
There are two options for specifying versions. The first one, which is indicating them in the URL, has already been described. The second option is about including a version in a request header. In general, the former solution is widely criticized. There are a lot of arguments like «THIS IS BAD!!!!!», but they do not seem convincing.
In fact, everyone chooses the option that works best for them. We would like to give a little piece of advice to those who want to try specifying versions in headers.
Don’t do it the following way:
You can easily insert more than one parameter in a header. Therefore, based on our experience the best practice is:
Accept: application/vnd.redkavasyl+json; version=2.0
Here is a good article on this point: Versioning REST Services.
RESTful architecture design
All resources in REST are entities. They can be independent like:
- GET /users — get all users;
- GET /users/123 — get a particular user with id = 123;
- GET /posts — get all posts.
There are also dependent entities, that rely on their parent models:
- GET /users/123/projects — get all the projects that a user with id = 123 has.
The above examples show that GET implies getting the entity you request. It is idempotent which means receiving identical data while performing the same requests. A successful request returns an entity representation combined with status code 200 (OK). If there is an error you will get back code 404 (Not Found), 400 (Bad Request) or 5xx (Server Error).
Let’s move to the POST method (the creation of a new entity):
- POST /users.
When creating a new entity you set parameters in the request body. For example:
The POST request is not idempotent, which means that if you send the same data in the repeat request, it will create an entity duplicate but with a different identifier.
After that you will get the result which may be status code 200 (OK), for example. Then the response will contain the data of a saved entity. For example:
It can also return status 201 (Created), resulting in the creation of a new entity. The server can specify its address in the response body. It is recommended to indicate it in the header “Location”.
The next request is PUT. It is used to update entities. When you send it the request body should contain updated entity data it refers to.
- PUT /users/123 — upgrade a user entity with id = 123.
The changes need to be indicated in the parameters. If updated successfully the request returns code 200 (OK) and the representation of the updated entity.
The last request is DELETE. It is simple to understand and is used to remove a specific entity according to an identifier.
- DELETE /users/123 — delete a user with id = 123.
If the removal is successful it returns 200 (OK) together with the response body that contains information about the status of the entity. For example, when you do not remove the entity from the database but just mark it as deleted, repeated requests will always return 200 (OK) and the response body with a status. DELETE can be considered as an idempotent request. It can also return code 204 (No Content) without the response body.
If you delete the entity from the database completely, the second request should return 404 (Not Found) because that resource is already removed and no longer accessible.
You can find more information in our blog article.