Getting REST Right

It seems everyone is building a REST API these days - this is great! It’s not easy, but there are a few key things you can do to make it easy for your consumers of your API.

URLs represent a resource #

Try to think carefully about your URL structure before you dive in, this will save a poor REST API later on.

Decide what resources you are dealing with. For these examples I’ll be looking at articles, attachments and users. In my setup, articles can have attachments, but users can’t, so for me it makes sense to have something similar to the following:

You may have noticed from the above URL schema that I have gone for singular URL nouns across the board. There is still some debate about whether singular or plural nouns are preferable, with plural seeming to win out but with most admitting it’s down to individual preference.

Most agree that you should stick to one or the other across the whole of your API, to keep the amount of learning to a minimum.

Verbs should not show up in your API URLs - if possible. “But what about /search?” I hear you cry.

Well if search is specific to an account then maybe having something like /article?q=search+term may be more appropriate to limit the results of the article list. Alternatively if you do have global search endpoint, then it’s probably appropriate to go for the /search endpoint.

Versioning #

Think about versioning your API from the public first release, unless your API is internal only and being consumed only by your own team can you probably get away with no versioning.

There are a couple of different ways you can go about this.

  1. In URL versioning (http://api.example.com/v1/article/43)
    • Probably the most popular, but unfortunately semi-breaks the “URLs represent a resource” principal
  2. Custom header (X-API-Version: v1)
    • Developers have to learn a new header just to use your API.
  3. Accept header (Accept: application/vnd.article-v1+json)
    • Developers can’t explore your API just using a browser.

There’s no easy answer, but I usually go for the compromise of in URL versioning for easy exploration of the API in combination with…

HATEOAS #

Standing for the easy to remember “Hypermedia As The Engine Of Application State”, it’s a fancy way of saying - return URLs to further resources in your API.

If you have a request to /v1/article, it should return something similar to the following:

GET /v1/article HTTP/1.1
Host: api.example.com
Accept: application/json

[
  {
    "id": 42,
    "name": "HG2G - Don't Panic",
    "url": "/v1/article/42"
  },
  {
    "id": 256,
    "name": "Two to the Eight",
    "url": "/v1/article/256"
  }
]

The url property of the article object allows the consumer to know how view the detail of the article object, without having to look at your documentation (you did write generate documentation right?). If you’re using Postman, you can just click on the link and it will take you straight to the next resource!

SSL Everywhere #

With the invent of Let’s Encrypt, there is no longer any excuse not to secure your API endpoint.

If you’ve got HTTPS enabled, and you receive a request to HTTP - just throw an error such as 400 Bad Request {"error": "HTTPS Required"} rather than redirecting to HTTPS.

Errors and HTTP status codes #

There are more HTTP status codes than you can shake a stick at. Also all good libraries should be able to read these, so you may as well utilise them.

Using these errors, especially for success can avoid you having to use an envelope in your response. If you’re returning a list of articles and everything was fine, you can just 200 OK, and return the list. There’s no need for:

{
  "status": 200,
  "status_msg": "OK",
  "articles": [
    {
      "id": 42,
      "name": "HG2G - Don't Panic",
      "url": "/v1/article/42"
    }
    ...
  ]
}

Caching #

I’m talking about both types of caching, server side and client side.

The server should tell the client if they need to get new data. You can use Last-Modified or Etags headers for this.

Also the server should keep a cache on the data from the datastore, especially if it’s immutable or you when the data expires. This will keep response times snappy and consumers happy!

Other stuff #

These are things I haven’t touched on in this article as it’s getting pretty long already, but you should consider:

 
1
Kudos
 
1
Kudos

Now read this

What’s in a version?

Building distributed systems in using a microservice pattern is hard. At my company we’re always looking for ways to automate any manual processes, or anything that is difficult. Computers don’t make mistakes, but humans aren’t... Continue →