Category: API

RESTful APIs and media-types

Evert Pot recently posted REST is in the eye of the beholder. Go ahead and read it; it's good!

It discusses the fact that most APIs that are self-described as RESTful are not hypermedia driven and hence are not actually RESTful as originally defined by Roy Fielding. Evert goes on to state that therefore the term "REST API" has changed to mean an HTTP API that isn't hypermedia-driven.

I think that what the world currently calls RESTful APIs fall short in more ways than just not serving Hypermedia links.

Media-types provide value

The majority of HTTP APIs out there do not reap the benefits of using media types correctly either. The majority seem to use application/json and call it done. The client gets absolutely no information about how to read the data, other than they'll need a JSON decoder… This is like having an HTML file and using a `.txt` file extension. It's correct in the sense that the the file is plain text, but absolutely useless for interpreting the file to render a web page.

Media types allow an API to inform the client how to interpret the data in the payload. This is arguably much harder than adding hypermedia to an API. The correct media types enforces the structure of the payload and also what the payload data means.

This is why most APIs just use application/json. If you're lucky, there's some documentation somewhere that explains things. Half the time, we seem to expect client developers to read the JSON and interpret it based on experience.

The best example of where this works well is the media type "text/html". Given a payload in this media type, a web browser can render the information in the way that the web developer (api server) automatically. This is because every server that sends a document with a text/html payload sends the same tags for the same meaning.

We can do this in the API world too, but it requires thinking about and is harder, so it doesn't happen…

There are three uses of media-types that I see in the world:

  • Plain: application/json (or application/xml
  • Vendor specific: e.g. application/vnd.github.v3+json
  • Standard: e.g. HAL, Collection+JSON or JSON-API, Siren, etc.

There is no practical difference between an API that uses a Plain media type and one that uses a Vendor specific one. As a client developer, you have no clue how to interact with the API or deal with its payload. To integrate with this API you need Google and hope you find enough documentation.

An API that uses what I've called standard media types give a client developer a leg-up. There's an official specification on how the data in the payload is organised. The standard is documented! This makes a difference.

You always need human-readable documentation to integrate with an API. A standard media type, implemented properly, makes it much easier. For starters you don't need to write as much as the standard has taken care of a good proportion of the boring bits. Something like HAL's curies provides an unambiguous way for the developer to find the right documentation for the endpoint they are dealing with.

JSON-API's pagination and filtering rules mean that I can write code once that will work with every API that uses JSON-API that I have to integrate with. This is powerful!

We can even go further with structured data as defined at schema.org to provide standardised field names for our data, but that's a topic for another day.

Evert is correct

I've used Evert's post to point out that when we talk about Hypermedia in a RESTful API, we mean more than simply putting in a few links in the payload.

Going back to Evert's article, he is correct; the term "REST API" is pretty much meaningless and at best simply means "An API that works over HTTP with some awareness of what an HTTP method is". The current term for an API that meets the constraints of REST is "Hypermedia API".

I think that providing an API with hypermedia & a well-documented media-type is beneficial for every API. APIs last longer than you believe and it's a competitive advantage if a developer can integrate with yours easier and faster than with your competitor's.

API errors are first class citizens

It seems to me that error handling is an afterthought in far too many APIs. When designing an API, I implore you to design your error handling too! The way that your API presents an error is key to a good API; developers integrating with your API will judge you on it.

Follow the HTTP rules

Just because it's an error doesn't mean that you can forget your HTTP. You need to be a great HTTP citizen with your error responses as well as with your successful responses. This means that you should:

  • Provide the correct status code
  • Honour the accept header
  • Send the correct content-type

Status code

In HTTP there are two acceptable ranges of status code for an error response: 4xx or 5xx.

The 4xx range are for client side errors and the 5xx range are for server side. In general, a 4xx means that the client needs to do something before it tries again. Some like 401 and 403 are related to permissions while most are related to ensuring that the message is a good HTTP message. Use 400 for validation errors.

Nearly all the 5xx are infrastructure related, so in your code you are most likely to be returning a 500 or 503 if something goes wrong at your end. If it's a 503, consider adding the Retry-After header so that your clients won't hammer your sever.

Media types

An error response should honour the data format indicated in Accept header that was sent by the client. If the client says that it accepts XML, then don't return an error in JSON or HTML! Similarly, ensure that you set the correct Content-Type header for your response! The client will use this in order to decode the error response.

Error response

Provide an error response. Your response should, at a minimum provide two pieces of information:

  • Application specific error code
  • Human readable message

The code is for the client application. It should never change and allows the client to perform different actions based on the specific error returned. An application error code is required because HTTP status codes are too granular and a client should never have to string match to work out what's going on!

The human readable error message is for your client developers. You want to help them as much as you can so that you don't get a support call! The message should provide information on what's gone wrong and in an ideal world, information on how to fix it.

All codes and messages should also be documented in your API documentation.

Use a standard media type

If you use a standard media type for your error, then you save on documentation and your clients will be able to use a library to handle them. This is a win-win situation. If you're using a media type which has error objects defined (e.g.JSON-API), then use that.

If not, use RFC7807: Problem Details for HTTP APIs. This defines both a JSON and XML format for error handling and there are libraries out there for most languages which will decode it for you.

In your documentation, encourage your clients to use an Accept header that includes all the media types you may return. e.g.:

That's it

It's not hard to have great error responses; you just need to care. Poor error response cause developers to give up with an API and go elsewhere, so it's a competitive advantage to get this right.

Developers integrating with your API will thank you.