Global store utility for an async operation lifecycle and chain of callbacks. It is a utility tool similar to continuation-local-storage which allows us to set and get values that are scoped to the lifetime of these chains of callbacks.
Note: async-store uses domain Node.js module under the hood.
It is recommended that you read about domain before using this package.
npm install @leapfrogtechnology/async-store
yarn add @leapfrogtechnology/async-store
Node Version | Async Store Version |
---|---|
14.17.0 and above | >= 2.0.0 |
14.17.0 and below | >= 1.0.0 < 2.0.0 |
const store = require('@leapfrogtechnology/async-store');
store.initialize()(callback);
function callback() {
store.set({ foo: 'Hello', bar: 'World' });
Promise.resolve()
.then(() => {
console.log('Value of foo: ', store.get('foo'));
})
.then(() => {
console.log('Value of bar: ', store.get('bar'));
})
.then(() => {
console.log('Value of foo: ', store.get('foo'));
})
.then(() => {
console.log('Value of bar: ', store.get('bar'));
});
}
On initialization the following output in the console is seen:
Value of foo: Hello
Value of bar: World
Value of foo: Hello
Value of bar: World
import * as store from '@leapfrogtechnology/async-store';
store.initialize()(callback);
function callback() {
store.set({ foo: 'Hello', bar: 'World' });
Promise.resolve()
.then(() => {
console.log('Value of foo: ', store.get('foo'));
})
.then(() => {
console.log('Value of bar: ', store.get('bar'));
})
.then(() => {
console.log('Value of foo: ', store.get('foo'));
})
.then(() => {
console.log('Value of bar: ', store.get('bar'));
});
}
On initialization the following output in the console is seen:
Value of foo: Hello
Value of bar: World
Value of foo: Hello
Value of bar: World
const { randomUUID } = require('crypto');
const express = require('express');
const store = require('@leapfrogtechnology/async-store');
const app = express();
const port = 3000;
// Initialize async store
app.use(store.initializeMiddleware());
// Set request Id in store
app.use((req, res, next) => {
store.set({ reqId: randomUUID() });
next();
});
// Get request Id from store
app.get('/', (req, res) => {
const reqId = store.get('reqId');
console.log(`Request Id: ${reqId}`);
res.json({ message: 'Hello World', reqId });
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
On request to http://localhost:3000
, the following output in the console is seen:
Example app listening on port 3000!
Request Id: 03d8bd27-9097-427a-9460-7d8d9576f156
const { randomUUID } = require('crypto');
const fastifyPlugin = require('fastify-plugin');
const store = require('@leapfrogtechnology/async-store');
const fastifyServer = require('fastify')({ logger: true });
const port = 3000;
fastifyServer.register(fastifyPlugin(store.initializeFastifyPlugin()));
fastifyServer.register((fastifyInstance, opts, done) => {
fastifyInstance.addHook('preHandler', (req, reply, done) => {
store.set({ reqId: randomUUID() });
done();
});
fastifyInstance.get('/', (req, reply) => {
const reqId = store.get('reqId');
console.log(`Request Id: ${reqId}`);
reply.send({ message: 'Hello World', reqId });
});
done();
});
const start = async () => {
try {
await fastifyServer.listen(port);
fastifyServer.log.info(`Server is listening at ${port}`);
} catch (err) {
fastifyServer.log.error(err);
process.exit(1);
}
};
start();
On request to http://localhost:3000
, the following output in the console is seen:
{"level":30,"time":1641890535421,"pid":12489,"hostname":"macbookpro","msg":"Server listening at http://[::1]:3000"}
{"level":30,"time":1641890535421,"pid":12489,"hostname":"macbookpro","msg":"Server is listening at 3000"}
{"level":30,"time":1641890539755,"pid":12489,"hostname":"macbookpro","reqId":"req-1","req":{"method":"GET","url":"/","hostname":"localhost:3000","remoteAddress":"::1","remotePort":51539},"msg":"incoming request"}
Request Id: aa6e86e9-c9d4-414a-8670-9aeaf2a8d932
{"level":30,"time":1641890539759,"pid":12489,"hostname":"macbookpro","reqId":"req-1","res":{"statusCode":200},"responseTime":3.7935830000787973,"msg":"request completed"}
Initialize the async store based on the adapter provided.
@param {AsyncStoreAdapter} [adapter=AsyncStoreAdapter.DOMAIN]
- Async store adapter to use.@returns {(params: AsyncStoreParams) => void}
- Returns a function that takes a callback which will be triggered once the store has been initialized.
const store = require('@leapfrogtechnology/async-store');
store.initialize()(callback);
function callback() {
// Do something with the store.
}
Middleware to initialize the async store and make it accessible from all the subsequent middlewares or async operations triggered afterwards.
@param {AsyncStoreAdapter} [adapter=AsyncStoreAdapter.DOMAIN]
- Async store adapter to use.@returns {(req, res, next) => void}
- Returns the express middleware function.
const express = require('express');
const store = require('@leapfrogtechnology/async-store');
// Initialize async store
app.use(store.initializeMiddleware());
Plugin to initialize the async store and make it accessible from all the subsequent plugin or async operations triggered afterwards from fastify server.
@param {AsyncStoreAdapter} [adapter=AsyncStoreAdapter.DOMAIN]
- Async store adapter to use.@returns {(fastifyInstance, opts, next) => void}
- Returns the fastify plugin callback.
const fastify = require('fastify');
const fastifyPlugin = require('fastify-plugin');
const store = require('@leapfrogtechnology/async-store');
// Initialize async store
fastify.register(fastifyPlugin(store.initializeFastifyPlugin()));
Check if the store has been initialized or not.
@returns {boolean}
- Returns either true or false.
if (store.isInitialized()) {
// Do something.
}
Persists properties in the store.
@params {any} properties
- Persist properties to set in store.@returns {void}
store.set({ foo: 'Hello', bar: 'World' });
Gets a value by a key from the store.
@params {string} key
- Key to get from the store.@returns {any}
- Returns the value persisted in the store bykey
which could benull
if key not found. Any error caught during the retrieval will be thrown and cascaded.
const foo = store.get('foo');
Gets all values from the store.
@returns {any}
- Returns all values persisted in the store. Any error caught during the retrieval will be thrown and cascaded.
store.set({ foo: 'Hello', bar: 'World', baz: 'Baz' });
// Get all the values from the store.
const values = store.getAll(); // { foo: 'Hello', bar: 'World', baz: 'Baz' }
// De-structure and get only few of them.
const { foo, baz } = store.getAll();
Gets multiple values from the store for each of the keys provided.
@params {string[] keys}
- Keys to get from the store.@returns {T[]}
- Returns an array of values. Order of the values is same as the order of the keys in the array.
const [a, b, sum] = store.getByKeys(['a', 'b', 'sum']);
Gets a value by a key from the store. If anything fails, it returns null
without emitting error event.
@params {string} key
- Key to get from the store.@returns {any}
- Returns the value persisted in the store bykey
which could benull
if key not found. Any error caught during the retrieval will be supressed andnull
value is returned.
const foo = store.find('foo');
Gets the unique store id created for the current context/scope. Example: If used in express, it returns unique store id per request.
@returns {string | undefined}
- Returns the unique store id.
const requestIdentifier = store.getId();
Gets the short unique store id created for the current context/scope.
Note: This is same as getId();
the difference being it only returns the first 8 characters.
@returns {string | undefined}
- Returns the short unique store id.
const requestIdentifier = store.getShortId();
- Node Web Server (TypeScript)
- Express Web Server (TypeScript)
- Koa Web Server (TypeScript)
- Fastify Web Server (TypeScript)
Check the CHANGELOG for release history.
Any types of contributions are welcome. Feel free to send pull requests or create issues.
Licensed under The MIT License.