What you need to know about REST.
We explore Representational State Transfer (REST), its strengths and why developers should consider it.
By Jorge Albaladejo, Senior Software Engineer at CauseLabs
If you are a developer and you’ve worked in any modern web application, I’m sure this term rings a bell for you. REST stands for Representational State Transfer. If you’re already familiar with the basics, hop over to our look at Advanced REST API design. If you’re in need of an intro, lets dive in and you’ll see why this architectural style has become a de-facto industry standard for back-end APIs.
REST is built on top of the HTTP standard, and it uses the same verbs (GET, POST, PUT, DELETE, OPTIONS, HEAD) than any web browser would use to navigate the internet. This makes REST open, standardized, and portable since any client being able to make HTTP requests can connect to an API and consume its data. As a result, any application (web, mobile, desktop, whatever) can connect to a REST API as long as both the client and the server are connected to the internet.
Since it’s based on HTTP, RESTful APIs must define the resources or functions they publish as unique URIs — also named endpoints. So the first thing when you design a REST API is to design these URIs or endpoints so that your data is well structured and your API easy to use and understand. This separation between the public interface, the collection of URIs of your API, and the business logic of your application hidden behind the URI schema makes REST a solid way of structuring your API logic. This way, REST decouples the application architecture, allowing each endpoint (function or module) to evolve independently. This reduces the application complexity, and the maintenance overhead.
Now, the fact that REST is considered an architectural style and not standard is because there’s some freedom to design the endpoints to better fit your needs. We’ll explore that later in this post.
Another important strength of REST is that it’s stateless. This simplifies the APIs significantly, leaving the responsibility of keeping the application state to the API clients. A REST endpoint receives a request with, potentially, some input data, and answers to that based on the API’s inner state, but not the client’s session or other combination of client actions.
This means that the queries to the API do not need to contain any information about the state or previous queries, which makes RESTful messages self-descriptive. A server response will contain all the information a client will need to decode and process it, including the MIME type and, in some cases, meta-links the client can follow to get related information. Since it’s not up to the server to keep the state, the client will have to decide what to do with the response. This greatly simplifies the server logic, allowing each client to decide how to react to a particular situation or state.
Because the messages are self-descriptive, a RESTful API can receive and return JSON, XML or any other representational format. REST APIs are, therefore, portable and interoperable, since they don’t depend on a particular data structure. A single API could, for instance, provide support for several data formats, allowing different clients to interact with its resources.
What does it look like?
Talking about the benefits of REST is much easier when illustrated with an example. Say we have a contact list service we want to open to the world. The data model of this service would look something like this:
We want to be able to read and edit contacts, and the same with their phone numbers and addresses (each contact may have more than one of these). How would we design this in a RESTful manner? First, let’s take a look at the available HTTP verbs. There’s more than these, but let’s keep it simple for now:
- GET: reads resources; this is the equivalent of opening the URI in your browser
- PUT: updates resources
- POST: creates new resources; this is the equivalent of submitting an HTML form
- DELETE: deletes resources
Now, here is where it gets tricky with REST. It’s an architectural style, not an opinionated standard. This means that there’s some room in how we can design the different endpoints of our API. What defines a REST endpoint or resource is its URI so let’s design a few of them:
- /contacts: will operate with contact resources
- /phone-numbers: will operate with phone number resources
- /addresses: will operate with address resources
But, how can we actually make things with these URLs and HTTP verbs? Let’s see:
- GET /contacts will produce a list of contacts
- POST /contacts will create a new contact with the data sent with the query
The same is true for /phone-numbers and /addresses. However, we’re only creating resources and reading lists, how could we access individual resources? We need another endpoint for that:
- GET /contacts/:id will return a contact identified by its unique :id
- PUT /contacts/:id will replace the information of the contact identified by :id with the data sent with the query
- DELETE /contacts/:id will delete the contact identified by :id
It is important to note that some verbs operate at a collection level only (POST) and others at a resource level only (PUT and DELETE). They should not be used otherwise unless there is a very good reason to do so — we’ll see a couple of examples later.
It’s important to note two best-practice rules here: resources in URLs should always be names, and the actions should be HTTP verbs. So POST /contacts is fine, and it tells us that we are creating (POST) a resource of type contact. POST /create-contact should be avoided, unless there is a very good reason to have it.
Now we can access individual resources, like contacts, or addresses… how can we keep the relation between them? If I wanted to get just the phone numbers or addresses for a given contact, how would I do that?
Again, I need a new endpoint:
- GET /contacts/:id/phone-numbers will return a list of numbers for this contact
- GET /contacts/:id/addresses will return a list of addresses for this contact
See the pattern? The structure is in the REST URLs, and the actions in the HTTP verbs. By properly designing the endpoints, the API will be uniform, comprehensive and easy to use.
In the same way, we can add resources to a contact:
- POST /contacts/:id/phone-numbers will create a new phone-number for the given contact
- POST /contacts/:id/addresses will create a new address for the given contact.
What about accessing individual related resources? Like, a given phone number or address of a given contact? Which of the following URLs should we use?
- GET|PUT|DELETE /contacts/:id/phone-numbers/:id
- GET|PUT|DELETE /phone-numbers/:id
By definition, URIs should represent a resource uniquely, and while two URIs could point to the same resource, it’s better if we avoid this duplication, in order to keep the API simple. The fewer endpoints, the easier it will be to maintain, use, and test. With this constraint, let’s choose the shorter URI:
- GET|PUT|DELETE /phone-numbers/:id
- GET|PUT|DELETE /addresses/:id
Following this principle, /contacts/:id/addresses/:id would be the same as /addresses/:id so we can discard the former approach in favor of the latter. However, /contacts/:id/addresses is not the same as just /addresses because the first one adds a filter that says “only the addresses that belong to this contact” while the second one will return all of them.
This can also be achieved by other means, like query parameters, which will allow us to do advanced operations with a collection of resources, like sorting, filtering and grouping. We’ll see about this in future chapters.
Sometimes, you need to provide a function that cannot be match by a resource name and an HTTP verb. In the real world, there are situations far more complex than just “create a resource”, or “replace the resource’s data with this”. Let’s see a couple of examples.
Say we want to not only create a contact, but do so from an existing one so that the user does not need to provide all the contact information up-front. How could we do that?
The purely REST approach would be: we cannot. Instead, we should request a contact (GET /contacts/:id) and then take this data, modify it accordingly and send it with a POST /contacts request. Sometimes this is fine, but sometimes this is not what we want. What would be our alternatives?
One approach would be to provide a contact ID along with the POST /contacts request. The server would understand this as “take the contact identified by :id, and create a new one based on its data. This is a bit obscure, in the sense that REST endpoints should be transparent about what they provide or do so that it’s more difficult to make a mistake.
Another approach would be to provide a specific endpoint that, unlike other RESTful resources, will only accept the HTTP POST verb. The endpoint name, in this particular case, could be a common English verb that expresses an action, so that it’s clear what this special endpoint does. For instance:
Pretty straightforward, right? This endpoint will create a copy of the selected contact, and will return it with the request. It only accepts a POST HTTP verb because it’s not idempotent, that is, subsequent queries to this resource will produce different results (just unlike a GET call, that will produce, if the server data didn’t change, the same results).
Another example would be attaching and detaching phone numbers from a contact. Imagine that phone numbers are entities by themselves (not identified by a contact). For instance, available land lines in an office. These numbers could be assigned to one or more contacts, and each contact would have at least one number assigned to them.
With our current design, we could do this:
But this would remove the phone number entirely, and that’s not what we want!
How could we detach a phone number from a contact without deleting it from the system? We need a specific endpoint to handle the detachment action. Again, REST is an architectural style, and so there’s different ways to achieve this.
For instance, we could override the DELETE HTTP verb so that, when used like this:
It will detach the number from the contact (aka “delete” the contact-number relationship), but will not delete the number from the system. This could work nicely, and it goes in the spirit of REST that resources are identified by names and actions by HTTP verbs.
We hope we’ve given you a useful insight into REST. If you wish to learn more, please jump into our look at post on advanced REST API design. You can also explore our resources below. As always, leave the CauseLabs development team comments or questions below if you’ve got some. We’d love to chat!