Amazing feature landed in Node.js - Breaking free from the request and avoid argument drilling with AsyncHooks
Tags: node, javascript
Published: 2020-04-06 23:04:47

I didn't pay too much attention to the features landed in Node 13, something I will definitely do from now as they have introduced an absolutely amazing new feature.

From frameworks in other languages like Laravel/PHP you might be used to getting the authenticated user like this:

```php
use Illuminate\Support\Facades\Auth;

// Get the currently authenticated user...
$user = Auth::user();
```

You can only get the authenticated user through the request as this is where you have access to cookies, headers, etc. Yet, the above code example doesn't mention anything about the request. Laravel provides us this expressive facade and does the dirty work under the hood, where it still accesses the request.

This is possible in PHP because each request is completely isolated from one another.

In Node.js, for a long time, you needed to get the authenticated user from the request and then pass down to every function that needs it.

```javascript
class PostController {
  async index({ auth }) {
    await new PostService().fetch(auth.user)
  }
}
```

Until now.

Node 13 comes with a new feature called [AsyncLocalStorage](https://nodejs.org/api/async_hooks.html#async_hooks_class_asynclocalstorage).

From the documentation it says: It allows storing data **throughout the lifetime** of a web request or any other asynchronous duration.

And here is an example:

```javascript
const { AsyncLocalStorage } = require('async_hooks');
const http = require('http');

const requestKey = 'CURRENT_REQUEST';
const asyncLocalStorage = new AsyncLocalStorage();

function log(...args) {
  const store = asyncLocalStorage.getStore();
  // Make sure the store exists and it contains a request.
  if (store && store.has(requestKey)) {
    const req = store.get(requestKey);
    // Prints `GET /items ERR could not do something
    console.log(req.method, req.url, ...args);
  } else {
    console.log(...args);
  }
}

http.createServer((request, response) => {
  asyncLocalStorage.run(new Map(), () => {
    const store = asyncLocalStorage.getStore();
    store.set(requestKey, request);

    setTimeout(() => {
        log('timeout');
    }, 2000);
  });
})
.listen(8080);
```

As you can see, when we wrap all our code within `asyncLocalStorage.run`, **anywhere** within the callback we can again retrieve any data we stored away. It's just like react's context API!

Building a nice abstraction layer around this is not too hard.

---

I'm excited about the possibilities this opens up. Here are some use cases I can think of:

- Getting and setting cookies
- Logging information about the current request
- session flashing
- Wrapping database calls in a transaction without passing the transaction object to each query (sometimes in separate function/class).

This was just meant to be a short introduction to this new feature. Obviously this also opens up room for complexity and dirty code. For example, it lets you access the request payload from anywhere in your application. Something you probably don't want to make use of in too many places as it couples the request with your entire code base. Well, let's see where this takes us!