Out of all the concepts, best practices, and principles that are talked about an API and its design, the one that usually given the lesser importance is an API error response. A part reason for this shortcoming is that everyone is happy till the time API is working fine. So lets put little thought into how should we treat the failure of an API function.
Who uses the API? Who do we build them for?
The API buzzword is very common these days. Almost every organization in the world has some form of API enablement plan, if not existing implementation.
Who uses the API? APIs are built for end-users. APIs are built to offer an abstraction on top of the underlying system so that the end-user(s) can have a standard way of accessing it, irrespective of the technology they are using. Even though APIs are built to be used by the end-users, who create meaningful applications with them, users are barely considered while designing APIs.
This is the reason a lot of people struggle with finding the right documentation for the APIs they are using and lack of standards across various APIs in industry. Talking about IT, it is highly difficult for a developer in an organization to use an API to its fullest without getting in touch with the creator of the API. Because no matter what, there are always some exceptions, special cases etc. which are specific to the API. Documentation is never sufficient.
Fixing the Problem
While creating an API, the most important concern to address is to meet all the technical requirements of the API. Now the question that comes to mind is that how does one create an API by keeping the end-user in mind. The key to this is to create an API which
- Gives ideal responses and response codes back
- Is self-documented
- Track-able for successful and error responses
- Reduces trial and error for the end-user
- Helps in error fixing.
Phew!! That sure does look like a lot to do. But is it that much of an effort??? Let’s find out.
Successful responses are the easiest to get done with. It’s a happy flow. Built fast and consumed even faster. The main catch is in handling the errors.
Response Codes — In an existential crisis!
HTTP response codes are well thought of standard, which enables numbers to tell the story of what happened. Often these are not used as they should be.
A 200 or 201 might not make a great deal of difference to the API creator, but to the user, it will let him decide whether the POST request created data or not. For an endpoint which just queues all the POST requests, returning a 202(Accepted) makes much more sense than returning a plain 200.
Let’s see what can an end-user interpret from HTTP response codes.
HTTP Response Code: 200
"message":"Something went wrong"
In the above case, the end-user would not know that the request failed unless he/she has written code to parse the text in response. As even in the case of failure, API is returning a 200. These type of responses are the most misleading ones. It might look absurd to a good developer, but these kind of responses are not so rare in IT world.
HTTP Response Code: 200
"message":"Request accepted. Will be processed shortly."
In Response 2, looking at the response code 200, the end-user might get an impression that the request processing is now completed, but it is only after reading the response message he/she would know that the request has been queued up. There is still a chance that the request might be rejected when it is eligible for processing later due to various reasons. Returning a 202, in this case, would have helped.
HTTP Response Code: 403
"message":"Forbidden. User does not have required permissions to access the requested resource."
In Response 3, although the response message clearly describes what went wrong, the end-user will never have to read it as the HTTP response code clearly states that the user was authenticated successfully but was not authorized to access the asked resource. In this way, just by looking at a number, the end-user would know what needs to be done to get this fixed.
Although these response codes are very well defined, they are not usually used the way they should be. A lot of APIs in IT return generic responses instead of case-specific ones as seen in the above examples. The key is to master them.
Return Meaningful Error Messages
It’s very easy to return an error in case your end-user has made a mistake. But what are the chances of your end-user not making the same mistake again? Is your API response helping her/him?
Let’s try to understand by an example: Let’s say our end-user is Sara. Sara is calling your POST endpoint on “/employee” resource to create a new employee. The endpoint expects employee email to be of the format email@example.com but Sara sends firstname.lastname@example.org while trying out the API and gets a 400 back. Now let’s see the possible API responses and what Sara can infer from each of them.
"message":"Data validation failed"
Here Sara knows that some field has bad data but she has no idea which one. Her only option is to go back to documentation(if any) and recheck every field that she is sending.
“message”:”Data validation failed for field ‘employeeEmail’ “,
“description”:”Field ‘employeeEmail’ does not have expected format”
Here Sara now knows that she has messed up the ‘employeeEmail’ field but does not know how to fix this. According to her, she sent an email address and validation shouldn’t have failed. Now she has no other option than looking up the documentation(if this has been documented)
“message”:”input validation failed”,
“validationRule”: “Employees should have company email address. Any other email address is not allowed.”
With this response, Sara knows exactly what went wrong and how to fix it. There is no need to reach out to the API creator or read any documentation.
A lot of modern APIs(also well-built ones) tend to give a link to the API documentation page related to the error in the response. This can make the error response even better by saving the end-user the effort he would put in to search for the right page in the API documentation.
Tracking — Boon for both API creator and End User
Validation is not the only form of error that can occur in an API call. There are a lot of business errors and transaction errors that can come up while processing a request. While its simple and easy to respond with the classic “Something went wrong. Try again later”, it makes much more sense to be a bit descriptive about the error and return a transaction ID.
“message”:”employee creation failed”,
“reason”:”workday service timed out while creating a new employee.”
This ID could be something unique to every request so that each request can be tracked separately. End-user can share this transaction/tracking ID with the API support team to find out what went wrong. On the other hand, it helps the API support team to crawl through the logs at a much higher pace and highlight such issues in their monitoring systems.
Although this might increase the time taken for an end to end development of the API, it reduces the amount of time taken in error resolution, API support and API maintenance.
While on one hand, following all this does not make a great deal of difference to API’s functionality, but on the other hand, it makes you a quality developer. The real kick in software programming is in solving a problem and not sitting in front of a black screen for hours damaging your eyes. So when we do solve a problem, let us put a bit of extra effort to make our solutions more usable.
Thanks for reading! And I would love to hear your suggestions and comments!
Also, if you are interested in learning more about an exciting new code quality product that reduces your Mule project costs by 79%, follow the below link :