Lessons learned designing APIs

Simple personal rules to avoid common mistakes and foster consistency while designing HTTP APIs.

Design the API first, write the service later.

Iterating over an API specification is easier and faster than in a real service. API specifications can autogenerate servers, clients, documentation, they will really save you more hours than you think. There are a bunch of API languages to help with this task 12

Even though I worked with RAML for several years, my personal favorite is OAS 3.0, it has teh good parts of RAML and OAS2, also several major companies backing it and creating tooling.

Hail the status codes.

As long as you use HTTP as underlying protocol, your API must follow the status codes. I've seen several times things like:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "ok": false,
  "errors": ["Some error message"]
}

It is ok to have ok: boolean as part of the response's body, the problem comes when it is not consistent with the status code, and that may generate friction while using different client tools or even confuse other services like load balancers.

The rule is easy even without using RESTful APIs

At root level, always return objects, never arrays.

If you are returning a list, you can always return an object containing a list:

// do
type Response = {
  data: Array<Element>
}

// instead of
type Response = Array<Element>

The chances you will have to add more metadata to your response are high, and compiled languages are not that happy parsing root level arrays.

Avoid "maps" when possible.

Compiled languages have a hard time optimizing generated code for maps or they don't even offer the feature without libraries. In almost any case the problem can be solved by returning an array of key-value pairs. It also adds the possibility to add more fields to the registers which is a good add-on for future features.

// do
type Response = {
  data: Array<{
    name: String
    value: String
  }>
}

// instead of
type Response = {
  data: Map<String,String>
}

There is only one date format

ISO86019, and if possible, use it without timezones. It works everywhere, even in JavaScript.

You don't need GraphQL.

It often make simple things complicated. It adds a lot of blackboxes to clients and servers.

Every attempt to use GraphQL I've seen only added complexity to the projects and created a ton of unoptimized requests, and even denial of services.

Final note

I hope those recommendations (more will be added as they come) will avoid you some headaches. One last but not least important suggestion, adopt a consistent standard, it may be REST[^rest] (although nobody does RESTful APIs correctly) or JSON:API[^jsonapi] or something that doesn't exist yet, it only has to be consistent and it has to make sense.


  1. Understanding API-first design
  2. Three principles of API-first design
  3. restfulapi.net
  4. RESTful API Modeling Language (RAML)
  5. Swagger (OAS 2.0)
  6. Open API Specification 3.0 (The good parts of RAML + Swagger)
  7. API Blueprints
  8. JSON:API
  9. ISO8601 Date and time formats