The Good Way to REST: Core Values And Mechanics

Berat Dağlar
REFINERI
Published in
10 min readDec 12, 2017

--

This is part 2 of a series on RESTful services where I talk about the things you should know when you’re designing a service layer. This piece will focus on core values and feature of REST rather than its inspirations. I highly suggest reading the first one as it will give you the basis for understanding a lot of concepts mentioned here.

Again, What is REST?

“REST is an architectural style that approaches machine-to-machine interaction problem on the foundations that made Web an achievement”.

This sentence summed up the first part. But what were the lessons REST extracted out of web? We can observe some overarching ideas upon many of the foundations and their properties that I listed in the previous section and this definition is going to be meaningless without finding out what those are.

Core Values

Imagine the whole internet having a contract or specification you need to download and internalise before letting you use it? Say, something like a description file. Every time every tiny detail of a website changes you should update your browser with it to access the most recent version of that page? This weird and nightmarish scenario with tight coupling and rigid contracts is a familiar one for developers that worked with SOAP-based services. The reason we do not have such necessities with the web is that it has its ways to be discoverable and predictable. Web achieves its flexible and loosely coupled structure by following these two fundamental principles.

Let’s give tangibles examples. Properties that increase discoverability are, for instance, having links (hypermedia) that allow the users to navigate around the resources; using visibility to let users know what they can and can’t do, and having clear conventions that enable them to guess what they don’t know. On the other hand, the things you can do to increase predictability include using pre-defined content types which signals how to interpret each resource; always responding with standardised status codes that let the users have preconfigured reactions, and preserving a sense of consistency by continually abiding by conventions that you’ve chosen.

When you create a self-professed RESTful service that values neither of these things, you have an API that is harder to use and understand than ancient alternatives from the perspective of your consumers. It is because you have eliminated the clarity that comes from using a contract and did nothing to counter that shortcoming. Combine this with some code generation stuff if you got lazy, and congratulations, you’ve managed to reanimate SOAP back from the dead in a worse, non-standard, zombie-like way.

Just like how good code should not need a documentation, good services are also the ones that don’t need any documentation (not the ones that don’t have any documentation though). So these are the ideas that you should always stick to when you’re in doubt about how to implement smaller details. Everything else, like specific architectures and techniques, is secondary to these values as you’ll quickly notice that decision you make about whether the resource names should be plural or singular is of little importance.

Enough With The Abstract Shit, Damn it!

So, up to this point, we have covered a lot of theoretical stuff. Which is nice, but as for the titular subject’s concern, could be annoying. So let’s fix that, shall we?

What is the good way to REST, and how do we do it?

We expose the entities in our domain model as resources.

This is more or less it. But it goes without saying that the first lesson you should take from this sentence is to have a domain model. With that as a transition, we could start listing the promised guidelines for the aforementioned good way.

1. Use Domain Driven Design

This is not the most straightforward requirement. There are simpler things you could do to start improving your back-end, but this is the most important one. It is never too early to start thinking about your domain.

You can have mostly individual endpoints that do their things, with their scopes overlapping most of the time. Or you can have a meaningful whole working together in harmony that will scale nicely. Encourage your developers to approach problems regarding how it affects the current domain model, rather than treating them as isolated issues.

Also, always try to think your endpoints that returns “collections” of representations as part of a relationship with another resource, rather than creating new concepts. For example, if your customers are expecting a service that returns their orders, the correct approach is not to create a new resource named “/my-orders”, but probably to create a relationship between user and orders with providing an endpoint like “/user/1/orders”.

Using domain driven design is always a good choice, but with RESTful services, it has double the importance.

Domain is love. Domain is life.

2. Have Unique URI’s For your Resources

Ok, let’s start climbing up the Richardson’s ladder. This one is pretty obvious and easy if you got your basics right. Most frameworks that you can use today and probably even your habits will push you in this direction anyway. But there was a time when API’s that we can define as “Swamp of POX” were commonplace and this is how you get out of it.

As mentioned in the previous part, do not have multi-purpose endpoints that change their content every time you visit them. It’s the only possible pitfall that I see people miss regarding this. If you put in some effort to define the services you need to provide in terms of resources, relations, and actions, then this should be easy enough.

3. Make Use of HTTP Verbs

Let’s continue with another easy one. Now that we are standing on level one, we have separate URIs for each resource. But if all requests for a resource use the same URI, don’t we need some way to differentiate their purpose? That’s where HTTP verbs (methods) could be of use. I’m going to list what you can do with them, in order of importance.

  • First and most importantly, if a request does not change the server side state, always use GET method; it’s going to do a lot for you when you start caching things. Conversely, if a request changes state, never use GET request. There will be better options, probably POST.
  • After that, mapping basic CRUD operations with POST, GET, PUT, and DELETE methods seems obvious, as it is a huge part of what people think of REST. Don’t forget to use GET, PUT, and DELETE in an idempotent way, which more or less means executing them once or multiple times shouldn’t make any difference as far as outcome.
  • Lastly, be aware that POST verb is kind of a wildcard with its purpose. Other than being used for the creation of a resource, conventionally it is used for all other requests that change the server-side state. You should limit these requests to updating a resource in a specific, named manner.
Named Action Example

These designated actions are more preferable compared to regular updates with the PUT verb since they give the control to the server-side and work better with HATEOAS as you will see later. While the usage of updates with PUT method is ok with primitive updates that only change the value of a property, updates with complex business logic should almost always define their own action.

  • There are other HTTP methods like HEAD, OPTIONS, PATCH with their specific uses. Learn what they do and use them at your leisure.

4. Strong URI Template Conventions

This one is a continuation of the verb stuff, but I’m gonna give it its own section cause we’re sidestepping a little. URI template is a range of URIs that you can map to an endpoint, like “/customer/{customer_id}”. You can obviously use a lot of different URI template formats with your services. But don’t. Try to narrow them down. Here are my preferred options:

  • Resource (/{entity_name}): a POST request should create a new one, sending GET should return all instances.
  • Instance (/{entity_name}/{instance_id}): for RUD operations of CRUD.
  • Relation (/{entity_name}/{instance_id}/{relation_name}): a GET request should return a collection defined under a parent model.
  • Action (/{entity_name}/{instance_id}/{action_name}): a POST request should execute a specific update operation related to the instance.

All other formats should be unnecessary, and you shouldn’t be needing them. For example, to provide access to a comment of a post, a GET request to the “/post/{post_id}/comments/{comment_id}” URI template could be used. But the same need could be satisfied with “/comments/{comment_id}” as well. For strong convention’s sake, I suggest omitting these complex templates entirely. Added complexity and decreased predictability of your API is not worth it.

5. Use Links (Hypermedia)

Ok, we only need one more step to until we reach the glory that was promised, well per Richardson anyway. But this is a big one since you’re going to have to take the gloves off. Most of the frameworks will not provide defaults for hypermedia usage, and quality of your implementation will largely depend on you. You need to know what you want to achieve beforehand.

In general, we want to make use of links in our responses to provide meta information about URI’s so that our user won’t feel lost. I’m going to list three increasingly useful bullet points that are increasingly harder to implement.

  • Self Links: Each representation should include a link that will guide the user to that representation, since we may not know the context in which it is accessed. Also, collection representations should include self-links related to paging. As in a link to access next page, first page etc.
  • Cross Resource Links: Each representation should provide links to the instances representations that it is related to, so that the user can traverse between the resources. Parent resources, child resources, or other relation services could be some of the endpoints these links point to. You may need a service discovery mechanism to properly implement this.
  • And then finally Actions Links: I say this is the cool one. Provide the links of endpoints that manipulate the resource instance, to the users who are authorised to access them. Adding HTTP method and accepted content-type info might as well be a good idea since we are trying let the user know what they can and can’t do, and how to do them. I’m going to go over this again in the next article while examining HATEOAS.

One last thing, I suggest using relative links rather than absolute. Absolute links will be harder to generate and will fuck things up when proxies and reverse proxies get in the mix anyway.

6. Make Use of Status Codes

There are more to the status codes than disappointing your users with a big 404 screen. They let the consumers interpret your responses in a shared way by putting them into brackets and allow HTTP clients to handle some of the needed behaviours.

There are discussions about which status code is exactly the best one to use in a specific situation. While these may be valuable, you shouldn’t get caught up in them. Conventions are critical, so as long as you make use of status codes in a transparent, consistent way, things should be alright. You could even create your codes out of the unused slots as big companies do it all the time. Just don’t mess with the ones that trigger HTTP client behaviour.

I’m not going to get into specifics of each of these. In my experience, the common ones you are going to need are 200, 201, 202, 204, 400, 401, 403, 405, 409 and 415. Check the full list to make sense of the current global conventions, and make your decisions yourself.

7. Make Use of Headers

HTTP Headers is another one of the powerful mechanics in your toolbox and will let you transfer useful meta information between client and server. Let me go over the useful ones:

  • Put a “Location” header in your response when creating a new resource, so that users know where to access the newly created instance.
  • Handling authentication through headers or secure cookies is a sensible approach. Depending on your needs check JWT and OAuth.
  • Put hashes of your representations in ETAG headers. More on this later in the advanced features part, also a very fun feature.
  • And for all the other custom needs, you may create your headers starting with “x-” as you like. But remember to disclose these transparently.

8. Always Transfer Your State’s Representation

All states in your system should exist only on the defined resources. And representations of those resources that are accessed through universal identifiers should be the only way to interact with the system. But, if a state changing endpoint only responds with bits of information it deems relevant to the to the current request, rather than the whole representation, consumer has to make assumptions about the current representation of the manipulated resource. So, always respond with the complete self-descriptive representation, providing a uniform interface. Then finally, you should be able to scream at people’s faces that you have a REST (Representational State Transfer) API with confidence.

Is this it?

Following guidelines listed in this article should be enough to say you got a RESTful back-end. But is it feature-rich enough that it will scale with your growing needs without lifting a finger? Unfortunately not. Next part should also be up in a week which I’m hoping will conclude the series. It will cover the advanced features that will lead to a more complete, mature API. Thanks for reading.

Update: Although a little bit late, last part is is also up and running.

A. Berat Daglar
REFINERI Consultant
https://refineri.co.uk

--

--