[NodeJS] - continuation local storage in nodejs using cls-hooked

Truong Bui

Published on: Last updated:

ts js nodejs async_hooks exspressjs cls-hooked tips

TABLE OF CONTENTS

  1. Problem
  2. Solution

Problem

We need to embed some data into each request, so that we can use it in any function call in the request lifecycle in expressjs

Solution

Using cls-hooked to store data in every request via middleware.

Step 1: Download cls-hooked package

Step 2: Create some util functions

File name: cls-hook-utils.ts
import cls from 'cls-hooked';
import * as express from 'express';

const ns = cls.createNamespace('your-namespace');

export const clsHookMiddleware = () => {
	return (req: express.Request, res: express.Response, next: express.NextFunction) => {
		ns.bindEmitter(req);
		ns.bindEmitter(res);

		// create hook context
		ns.run(() => {
			// example - set request context
			np.set('time', Date.now());
			next();
		});
	};
};

export const getClsHookContext = <T>(key: string): T | undefined => {
	if (ns.active) {
		return ns.get(key) as T;
	}
};

Step 3: Use clsHookMiddleware as expressjs middleware

File name: app.ts
import express from 'express';

import { clsHookMiddleware, getClsHookContext } from './cls-hook-utils';

const app = express();
app.use(clsHookMiddleware());

Step 4: Get data

File name: app.ts
...

app.get('/', (req, res) => {
	const requestTime = getClsHookContext('time');
	res.send(`Your request time is ${requestTime}`);
});
WARNING:
You have to create cls hooked context ns.run() before you can get data. If not, you will get Error: No context available. ns.run() or ns.bind() must be called first. when you try to get data via hook.
I don't go into detail about cls-hooked or async-hook in this post. If you're interested, you can read more about it here or here

Hope you find this article useful. If you have any questions, please let me know in the comment section below. 👇