Best Practices for your REST API

As Android developer, I almost always need to request information to a REST API either fetch data from server or send them. Throughout my working experience, I have had to integrate with APIs we have developed and other third parties we had to integrate with, but I have seen a list of errors everybody should avoid developing a REST  API.

Avoid returning always the same HTTP status code

I have seen some REST APIs that always returned a 200 status code. As no errors were returned in this API, you could think everything was perfect, right? But it was not, it was a mess indeed. How can you differ successful responses with error responses coming from client or server? Regarding body? This logic should be in backend, never in client! Client must always be stupid – the more the merrier. It should not contain logic about server API. If server is changed, it may be causing errors in client if it is not updated at the same time; fact that is very common with mobile apps.

My recommendation is to use HTTP status codes for server responses. You can find the following status codes according to RFC7321

  • 1xx Informational response
    • 100 Continue
    • 101 Switching protocols
    • 102 Processing
  • 2xx Successful response
    • 200 OK
    • 201 Created
    • 202 Accepted
    • 204 No content
    • etc.
  • 3xx Redirection
    • 300 Multiple choices
    • 301 Moved permanently
    • 302 Found
    • 304 Not modified
    • 305 Use proxy
    • etc
  • 4xx Error in client
    • 400 Bad request
    • 401 Unauthorized
    • 403 forbidden
    • 404 Not found
    • 410 Gone
    • etc.
  • 5xx Error in server
    • 500 Internal server error
    • 501 Not implemented
    • 502 Bad gateway
    • 503 Service unavailable
    • etc

Not use different error response formats

Related to what I described above, if you keep the same error format, you’ll simplify clients to integrate with your API. For example, you can define a structure as following and has any middleware in your server detecting error responses and wrapping error in a response such as


    Response status code: 403
    Response body
    {
        code: 5,
        message: "Error message"
    }

Furthermore, servers must not return error stack-trace, they should be handled.

Differ HTTP methods

Some engineers start to develop REST APIs with a single HTTP method, even coding some protected web services by authentication. I have found 2 cases, when all requests implement GET method sending session information as query param or when all requests implement POST method with session data information included in the body. They are not well designed, we have different methods to do different actions.

HTTP defines a number of standardized methods. Let me summarize the most used with HTTP definition:

  • GET: Transfer a current representation of the target resource.
  • POST: Perform resource-specific processing on the request payload.
  • PUT: Replace all current representations of the target resource with the request payload.
  • DELETE: Remove all current representations of the target resource.

Ok, you will be wondering, what does it stand for? How can I apply to my REST API? No worries, I will provide a example.

Imagine we are developing “users” resource, we need to create 5 basic web services:

HTTP Method PATH BODY Successful Response
Fetch all users GET /users List of user representations
Get a user GET /users/<userId> User representation
Add a user POST /users User representation User representation
Edit a user PUT /users/<userId> User representation User representation
Delete a user DELETE /users/<userId>

As you can see, it’s very clear to know what each resource does.

Versioning your API

Nowadays, companies usually want to have published their apps in Google Play or AppStore and they are continuously releasing new versions of their app, but what about server? It is also increasing in functionalities. The problem comes when users don’t update when there is a new update – it frequently happens. You can’t afford having a server per app version, then what can I do? The only solution is to have different versions in your API.

Also, remember when you have different versions of your API you must think in backward compatibility. Don’t break anything that it’s currently working after a new release.

If you only had to support a website, you could forget this advise, but we are in a world where mobile applications are everywhere; so sooner or later, your product will be published in apps markets.

 

Include session token in headers

Most APIs have private requests, requests can only be reached if there is an active session. Sometimes, developers include session token as part of URLs using a query param  or implementing all requests with POST method to send session token as a param in the body. It does not make sense to implement “Get all users” web service with a POST method. As you have learnt above, this method should be GET.

Therefore, support  HTTP “Authorization” header in your API and send it in all requests with the user credentials to authenticate with server. It can flexible and you can adapt to your authentication protocol easily.

Internationalize your API

It’s very common to return error, successful or informative messages in our API. As I have commented above, the client must not contain any server logic, not even for messages. Sometimes, we need to show those messages in the client. Then, we need to send internationalized according to client device. But, how can the client request messages in a language?

Supporting “Accept-Language” header in our API and clients are responsible to send its language in every request using this request header. For example: setting “Accept-Language: es” you should get messages in Spanish.

I really recommend you to use any i18n library to support this, although you are currently supporting just one language. In the future, you will need to support more than one and it will be a nightmare to replace hard-coded strings by i18n tokens.

Paginate your results

Implement pagination in all web services you think you will return too much data. You will reduce the response time and data sent to clients. If that client is our mobile device, think you might not have a good internet connection, as consequence,  as less time and information is returned, it will be better.

Respond what you are requesting

If you are requesting to a resource, return its representation or a list of them; avoid responding with something different. You might think you are doing in the right way, but I will show you a common example when people get wrong.

If we call to the web service to fetch all users, some APIs return a response like the following one:

{
    "users": [
        {
            "name": "John",
            "surname": "Smith",
            "age": 25
        },
        {
            "name": "Peter",
            "surname": "Potter",
            "age": 47
        }
    ]
}

Do you think it is OK? No, this response is not correct due to you are getting an object with a list of user representations. You should have gotten just a list of user representations.

[
    {
        "name": "John",
        "surname": "Smith",
        "age": 25
    },
    {
        "name": "Peter",
        "surname": "Potter",
        "age": 47
    }
]

Return correct data types

Try to return correct data types and take advantage of null objects in case you don’t have that information.

For example, imagine we want to return user information. Fields we have from users are name, surname and age.

{
    "name": <string>,
    "surname": <string>,
    "age": <int> 
}

If age were not mandatory, it could be null. In that case, avoid using age as string and return an empty string (“”), return null when it is unknown.

{
    "name": "John",
    "surname": "Smith",
    "age": null
}

Model integrity could be affected and you will avoid useless datatype conversions.

Test your backend with automated tests

Tests should be mandatory in all projects but even more with the part that has all product logic. They will help you not to mess up or including new bugs in features that are currently working. So, next time you will start to develop a new feature in your backend, include some integration and unit tests, you will thank you.

tests

Use HTTPS over HTTP and valid certficates according to your clients

Nowadays, if you want to have a secure API, firstly you need to run it with a HTTPS scheme, this fact is known by most people. But, be careful when you are choosing the certificate that you want to use in your app. Avoid self-signed certificates or old encryption algorithms. If you have any doubt, read encryption algorithms supported by your clients (mobile devices, browsers, etc) and choose one according to your needs.

Make conditional requests

Can we do? Of course you can! One of my favorite example is to use If-Modified-Since request header. Why? Because we can cache the last response date we received and ask for changes since that date. This is a very good practices for mobiles devices due to users usually don’t have unlimited data plans.

More practices?

Of course I might forget more good practices and  C’mon! Don’t be shy and comment them! I love learning something new and we can extend this article or create a new one.

Related articles

Clean Architecture design in NodeJS

Test automation for an API: Postman, Newman and Jenkins

The best (and worst) of Mocha, JavaScript unit testing

Share on LinkedInTweet about this on TwitterShare on FacebookShare on Google+Buffer this page

6 thoughts on “Best Practices for your REST API

  1. Really good article, I knew most of them but the conditional request make me think about how improve our API using it. Good job Jose Carlos!

  2. Most of the advice is good except for “Respond what you are requesting”.

    Rest API request and response bodies will change over time. You want to be able to make additive changes to your REST API. For that reason you should never return a JASON array as the root type for your REST response, always an object; even for bulk / list requests.

    • But, if you want a RESTful API and you fetch “/users” as I described in the example, it makes no sense to return something else that does not fit with user model. You are asking your server about users, no for that extra information.

      Imagine that “/users” WS returns a collection of users and administrators

      
      
      {
          "users": [
              {
                  "name": "John",
                  "surname": "Smith",
                  "age": 25
              },
              {
                  "name": "Peter",
                  "surname": "Potter",
                  "age": 47
              }
          ],
          "admins": [
              {
                  "name": "Peter",
                  "surname": "Potter",
                  "age": 47
              }
          ]
      }
      
      
      

      Wouldn’t be it better to add an attribute in user model to specify if a user is an admin?

      
      [
          {
              "name": "John",
              "surname": "Smith",
              "admin": false,
              "age": 25
          },
          {
              "name": "Peter",
              "surname": "Potter",
              "admin": true,
              "age": 47
          }
      ]
      
      
      

      I agree with you REST API can and will change, but if the response does not fit with collection model, they are semantically different and you should split it in another request.

  3. Using the standardized HTTP elements like response codes and headers are not best practices, but requirements for an API to be called REST.

    What I miss is not using JSON, but explicit content types to identify what kind of resources are exchanged. JSON is just a blob of key/values with no meaning.

    • Hi,

      I am pretty sure I have missed some other good practices and use of content types is one of them. That’s why I ask in the end of this post about missing good practices.

      Thanks for your comment! 😉

Leave a Comment

By completing the form you agree to the Privacy Policy