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
- 3xx Redirection
- 300 Multiple choices
- 301 Moved permanently
- 302 Found
- 304 Not modified
- 305 Use proxy
- 4xx Error in client
- 400 Bad request
- 401 Unauthorized
- 403 forbidden
- 404 Not found
- 410 Gone
- 5xx Error in server
- 500 Internal server error
- 501 Not implemented
- 502 Bad gateway
- 503 Service unavailable
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
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:
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:
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.
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.
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.
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.
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.
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.