How to implement async operations in your Express REST API
Tags: node, rest, express, tutorial
Published: 2021-08-16 07:37:36

This article is a continuation of a series about how to build a REST API in Node.js. In the [first article](https://dev.to/bhaeussermann/building-a-node-js-rest-api-14o7) of this series, we built a rudimentary REST API for managing a list of employees. However, instead of using a real database, the `EmployeesService` simply maintained the list of employees in memory. Had it implemented actual calls to a database, the methods would likely have been asynchronous, returning promises rather than performing the work synchronously. In this post we will discover how to properly add support for async functions.

Let's change the `EmployeesService.get()` method to be asynchronous and see what happens. By adding the following `await` statement we simulate the database query taking 1 second before it returns the results:

{% gist https://gist.github.com/bhaeussermann/88583970893dbab25a758f9b1fc4140e %}

Now, if we call `GET localhost:3000/employees/1` the response we get is the empty object `{}`. Keep in mind that in JavaScript an `async` method effectively returns a `Promise` that resolves when the method completes. It appears that in *employees-controller.js* where we call `res.json()`...

{% gist https://gist.github.com/bhaeussermann/9c3cf8cf3a29b01bf3e191460ddf7ac5 %}

Express just *stringified* the `Promise` object passed into `res.json()` rather than awaiting it and using the resolved value. We need to pass the *resolved* value into `res.json()` instead:

{% gist https://gist.github.com/bhaeussermann/69535099cab9eb14b9ee75115156f247 %}

Testing the call using our REST client, this seems to work. However, when we request an employee that doesn't exist, something weird happens. The request hangs and eventually times out. 

This is because the request-handler function passed into the `get()` method above is now async. The `get()` method handles the case where the passed function throws an error by making the request respond with an error code. Now that the method is async, what happens instead is that the function returns successfully returning a `Promise` which eventually gets rejected, and `get()` doesn't handle this as expected.

We can make this route handle errors correctly by using the third `next` parameter passed into the request-handler function like so:

{% gist https://gist.github.com/bhaeussermann/3772a8fa32ffeb47ce3b99d5928561b9 %}

Running the request for an employee that doesn't exist now returns the expected response.

Suppose now that all of our request-handler functions were async (and in a real-world application, most of them will be). We would have to wrap every operation's code into a try-catch block, and pass the error into the `next` function to prevent a request hanging forever should an error occur. This is far from ideal. Thankfully, the [express-async-handler](https://github.com/Abazhenov/express-async-handler) provides a much more convenient way of dealing with errors.

First, use `npm` to add the package as a run-time dependency:

```
npm install --save express-async-handler
```

And use it in `EmployeesController` like so:

{% gist https://gist.github.com/bhaeussermann/f9c6d0bc0529e49661da8ea3b07a5e25 %}

*Of course, if we had not had to deal with the particular case of the 404, then the try-catch block would not have been needed since the `asyncHandler()` deals with any errors that might happen.*

As long as we remember to pass each async operation's function into `asyncHandler()`, we can rest assured that whenever an error occurs within the operation, it will still return the correct error code and message and not just hang until it times out.

Future posts will show how we can add additional middleware such as for [adding request / response validation](https://dev.to/bhaeussermann/adding-request-and-response-validation-to-your-express-rest-api-36ia) and [Swagger documentation](https://dev.to/bhaeussermann/adding-a-swagger-ui-page-to-your-express-rest-api-3cbc) thanks to Node.js packages available for this.

*The code for the API developed in this series of articles is available on GitHub [here](https://github.com/bhaeussermann/node-js-rest-api).*