Controlling axios HTTP error handling and test it using nock + Jest.
Axios is a popular Promises based HTTP client library. It offers nice abstraction over the core node http module. This post explains the default error propagation mechanism of axios library, and how to control it using the axios request configuration. Finally, how you can test all these using nock, HTTP mocking library and Jest test library.
This article assumes the reader has good understanding of how Promises work and how async/await create a syntactic sugar layer over Promises to make asynchronous execution looks like synchronous.
A simple express based RESTFul API Resource.
To keep the focus on the topic of this article I am going to use a really simple express based RESTFul API resource with simple service layer which calls a mocked REST endpoint.
This is the service layer. It simply calls the mock REST endpoint which returns customer accounts and returns that data as it is to the controller layer. It uses axios as the HTTP client.
And our simple RESTFul resource will be operate on ‘/customers’ path.
This set up works perfectly if the requirement is to treat any 200 OK response from the backend as success and any other response as error and catch at the ‘/customers’ router catch block and send a error response to the client.
What if your backend has diverse set of errors ?
Most of the time this is the case, backends have more than one error response and those responses return with non 200 range HTTP status codes. And these errors have business related meanings in the given context.
For example if the ‘/account’ service responded with 403 Forbidden because your access_token is invalid. The default behaviour of axios library is to reject the Promise and return a JavaScript Error object.
The Error object returns by the Promise rejection is not much helpful if you want to create a custom error based on scenario and respond with meaningful error message. Have a look on the Error object returned by the Promise rejection.
The name of the Error object is ‘Error’ and the only way to identify what actually happed is to look at the message string.
validateStatus to rescue.
Next question is how can we tell axios client not to reject the Promise when HTTP status code 403 or any other non-200 range. There is a configuration named ‘ validateStatus’ which can be used to control above default behaviour as we want.
The default is as follows.
But we can change it to something like following based on your scenario.
The most important part is to use this configuration. First, you need to create an axios instance with this configuration and you should use newly created axios instance to call the services.
We have the control, what do we do with that ?
Yes, above configuration does not help much if you do not control the error propagation with good care. So let’s get to it.
I have created two custom errors ‘InvalidTokenError’ and ‘CustomerAccountNotFoundError’ consecutively match to 403 Forbidden , 404 Not Found HTTP status form the ‘/accounts’ service.
And after improving the error detection to be based on the HTTP status code. The service layer should be capable to emit custom errors.
And now the emitting error will have more meaningful shape. One could always argue that we have lost the error context information from the HTTP layer by doing this. But in this article I am assuming that the reader need to handle the HTTP error status codes by converting those to meaningful errors within the application.
Error handling at the controller layer
Now with above newly built tool set we can improve the custom error handling at the controller layer as shown in the index.js code.
Error propagation control is done, how can I test it ?
To test this I am using nock, a HTTP mocking library and Jest , a JavaScript testing framework from Facebook. Setting up both above libraries to your project is really simple and documentation of both libraries does a fantastic job on that hence I am not going to describe it here.
The test suit below covers both InvalidAccessToken and CustomerAccountNotFound scenarios. Note that here also I use the async/await with try catch to catch the error and inspect it using expect.
And the results should be
Conclusion
In this article I have shown how to control of the axios HTTP client library’s error emitting mechanism, and how to set up HTTP mocks using nock to test the scenarios using Jest. If you are an API developer who uses express/node.js to develop RESTFul APIs hope this will add a handy tool to your developer tool kit.
Happy Coding :)