README
fast-als
Asynchronous local storage implementation which provides an agnostic and performant approach no matter your version of node.
This package is a wrapper around both the populer cls-hooked library as well as the Node v13+ AsyncLocalStorage.
It will choose the right one to implement based on your version of Node.
This library is great for creating a thread local like implementation for your Express, Koa, Fastify, or Restify implementations to provide a local store per call. This library ensures that all values stored within a scope will only pertain to that scope (scope creep in this instance is lethal to data integrity).
For instance, if you are using an ORM and you have some type of beforeHooks to save user information. You could try to save the calling user's information in some pre request handler by storing a value in a service to be used later by the hooks to save the proper user making the api call. However, if another user made a simultaneous call, someone's info could/would be overwritten in this case. This library ensures that will not happen.
Examples
The following examples show how this can be set up in some of the more familiar Node API frameworks. These examples can be run from the examples directory.
Fastify
const fastAls = require('fast-als');
const fastify = require('fastify')({ logger: true })
fastify.addHook('onRequest', (req, reply, done) => {
fastAls.runWith({
user: { id: 'system' } // sets default values
}, () => {
done();
});
});
fastify.addHook('preHandler', (req, reply, done) => {
// overrides default user value
fastAls.set('user', { id: 'fastifyUser' });
done();
});
// Declare a route
fastify.get('/', async (request, reply) => {
return {
user: fastAls.get('user')
}
});
// Run the server!
const start = async () => {
try {
await fastify.listen(3000);
fastify.log.info(`server listening on ${fastify.server.address().port}`);
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
}
start();
Express
const fastAls = require('fast-als');
const express = require('express')
const app = express()
const port = 3000
app.use((req, res, next) => {
fastAls.runWith({
// overrides default user value
user: { id: 'system' } // sets default values
}, () => {
next();
});
});
app.use((req, res, next) => {
fastAls.set('user', {
id: 'expressUser'
});
next();
});
app.get('/', (req, res) => res.send({ user: fastAls.get('user') }))
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
Restify
const fastAls = require('fast-als');
const restify = require('restify');
var server = restify.createServer();
server.pre(function (req, res, next) {
fastAls.runWith({
user: { id: 'system' } // sets default values
}, () => {
next();
});
return;
});
server.use(function (req, res, next) {
// overrides default user value
fastAls.set('user', { id: 'restifyUser' });
next();
});
server.get('/', (req, res, next) => {
res.send(fastAls.get('user'));
});
server.listen(8080, function () {
console.log('%s listening at %s', server.name, server.url);
});
API
Table of Contents
fastAls
Asynchronous Local Storage wrapper that will run regardless of Node version.
runWith
The start of creating an asynchronous local storage context. Once this method is called, a new context is created where get and set calls will set and return values as expected.
Parameters
defaults
object Sets the default values. A convenience so that you don't have to check to see if a value is there and set it to something else.callback
fastAls~runWithCallback This is the code to be executed first within the new context that is created
Examples
const fastAls = require('fast-als');
function firstCallInScope() {
// override user
fastAls.set('user', { id: 'overwrittenUser'});
}
function secondCallInScope() {
// will print the user set in firstCallInScope
console.log(fastAls.get('user'));
}
fastAls.runWith({ user: { id: 'someUser' } }, () => {
firstCallInScope();
secondCallInScope();
});
set
Sets a variable for a given key within running context (started by runWith). If this is called outside of a running context, it will not store the value.
Parameters
key
string the key to store the variable byvalue
any the value to store under the key for lookup later on.
Examples
const fastAls = require('fast-als');
function callInScope() {
// override user
fastAls.set('user', { id: 'overwrittenUser'});
}
fastAls.runWith({ user: { id: 'someUser' } }, () => {
callInScope();
});
const fastAls = require('fast-als');
function callOutOfScope() {
// this never gets set
fastAls.set('user', { id: 'overwrittenUser'});
}
// calling this won't store the variable under the key
callOutOfScope();
get
Gets a variable previously set within a running context (started by runWith). If this is called outside of a running context, it will not retrieve the value.
Parameters
key
string the key to retrieve the stored value
Examples
const fastAls = require('fast-als');
function callInScope() {
// prints default user
console.log(fastAls.get('user'));
}
fastAls.runWith({ user: { id: 'someUser' } }, () => {
callInScope();
});
const fastAls = require('fast-als');
function callInScope() {
// prints default user
console.log(fastAls.get('user'));
}
fastAls.runWith({ user: { id: 'someUser' } }, () => {
callInScope();
});
// calling this will return undefined
callInScope();
fastAls~runWithCallback
The code to be executed after the new asynchronous local storage context is created.
Type: Function