From 0244b63beb72703a06bcf34b50e1a28d75857715 Mon Sep 17 00:00:00 2001 From: Manuel Spigolon Date: Sun, 2 Mar 2025 23:26:12 +0100 Subject: [PATCH] feat: expose getStore() (#215) --- README.md | 5 +- index.js | 3 + test-tap/requestContextPlugin.e2e.test.js | 68 ++++++++++++++++------- types/index.d.ts | 1 + 4 files changed, 55 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 071ee74..e384c3b 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,10 @@ app.addHook('onRequest', (req, reply, done) => { app.get('/', (req, reply) => { // requestContext singleton exposed by the library retains same request-scoped values that were set using `req.requestContext` const user = requestContext.get('user'); - reply.code(200).send( { user }); + + // read the whole store + const store = req.requestContext.getStore(); + reply.code(200).send( { store }); }); app.get('/decorator', function (req, reply) { diff --git a/index.js b/index.js index 29e6949..70b545e 100644 --- a/index.js +++ b/index.js @@ -19,6 +19,9 @@ const requestContext = { store[key] = value } }, + getStore: () => { + return asyncLocalStorage.getStore() + }, } function fastifyRequestContext(fastify, opts, next) { diff --git a/test-tap/requestContextPlugin.e2e.test.js b/test-tap/requestContextPlugin.e2e.test.js index 1168e82..36e0fa5 100644 --- a/test-tap/requestContextPlugin.e2e.test.js +++ b/test-tap/requestContextPlugin.e2e.test.js @@ -58,7 +58,7 @@ test('correctly preserves values set in prevalidation phase within single POST r const response1Promise = request('POST', url) .send({ requestId: 1 }) .then((response) => { - t.assert.deepStrictEqual(response.body.storedValue, 'testValue1') + t.assert.strictEqual(response.body.storedValue, 'testValue1') responseCounter++ if (responseCounter === 2) { resolveResponsePromise() @@ -68,7 +68,7 @@ test('correctly preserves values set in prevalidation phase within single POST r const response2Promise = request('POST', url) .send({ requestId: 2 }) .then((response) => { - t.assert.deepStrictEqual(response.body.storedValue, 'testValue2') + t.assert.strictEqual(response.body.storedValue, 'testValue2') responseCounter++ if (responseCounter === 2) { resolveResponsePromise() @@ -100,8 +100,8 @@ test('correctly preserves values set in multiple phases within single POST reque const preValidationValue = req.requestContext.get('preValidation') const preHandlerValue = req.requestContext.get('preHandler') - t.assert.deepStrictEqual(onRequestValue, undefined) - t.assert.deepStrictEqual(preParsingValue, undefined) + t.assert.strictEqual(onRequestValue, undefined) + t.assert.strictEqual(preParsingValue, undefined) t.assert.ok(typeof preValidationValue === 'number') t.assert.ok(typeof preHandlerValue === 'number') @@ -137,7 +137,7 @@ test('correctly preserves values set in multiple phases within single POST reque const response1Promise = request('POST', url) .send({ requestId: 1 }) .then((response) => { - t.assert.deepStrictEqual(response.body.storedValue, 'testValue1') + t.assert.strictEqual(response.body.storedValue, 'testValue1') responseCounter++ if (responseCounter === 2) { resolveResponsePromise() @@ -147,7 +147,7 @@ test('correctly preserves values set in multiple phases within single POST reque const response2Promise = request('POST', url) .send({ requestId: 2 }) .then((response) => { - t.assert.deepStrictEqual(response.body.storedValue, 'testValue2') + t.assert.strictEqual(response.body.storedValue, 'testValue2') responseCounter++ if (responseCounter === 2) { resolveResponsePromise() @@ -174,8 +174,8 @@ test('correctly preserves values set in multiple phases within single POST reque const preValidationValue = req.requestContext.get('preValidation') const preHandlerValue = req.requestContext.get('preHandler') - t.assert.deepStrictEqual(onRequestValue, 'dummy') - t.assert.deepStrictEqual(preParsingValue, 'dummy') + t.assert.strictEqual(onRequestValue, 'dummy') + t.assert.strictEqual(preParsingValue, 'dummy') t.assert.ok(typeof preValidationValue === 'number') t.assert.ok(typeof preHandlerValue === 'number') @@ -191,9 +191,9 @@ test('correctly preserves values set in multiple phases within single POST reque return request('POST', url) .send({ requestId: 1 }) .then((response) => { - t.assert.deepStrictEqual(response.body.storedValue, 'testValue1') - t.assert.deepStrictEqual(response.body.preSerialization1, 'dummy') - t.assert.deepStrictEqual(response.body.preSerialization2, 1) + t.assert.strictEqual(response.body.storedValue, 'testValue1') + t.assert.strictEqual(response.body.preSerialization1, 'dummy') + t.assert.strictEqual(response.body.preSerialization2, 1) }) }) }) @@ -219,7 +219,7 @@ test('does not affect new request context when mutating context data using no de return request('GET', url) .query({ action: 'setvalue' }) .then((response1) => { - t.assert.deepStrictEqual(response1.body.userId, 'abc') + t.assert.strictEqual(response1.body.userId, 'abc') return request('GET', url).then((response2) => { t.assert.ok(!response2.body.userId) @@ -251,10 +251,10 @@ test('does not affect new request context when mutating context data using defau return request('GET', url) .query({ action: 'setvalue' }) .then((response1) => { - t.assert.deepStrictEqual(response1.body.userId, 'abc') + t.assert.strictEqual(response1.body.userId, 'abc') return request('GET', url).then((response2) => { - t.assert.deepStrictEqual(response2.body.userId, 'bar') + t.assert.strictEqual(response2.body.userId, 'bar') }) }) }) @@ -283,10 +283,10 @@ test('does not affect new request context when mutating context data using defau return request('GET', url) .query({ action: 'setvalue' }) .then((response1) => { - t.assert.deepStrictEqual(response1.body.userId, 'bob') + t.assert.strictEqual(response1.body.userId, 'bob') return request('GET', url).then((response2) => { - t.assert.deepStrictEqual(response2.body.userId, 'system') + t.assert.strictEqual(response2.body.userId, 'system') }) }) }) @@ -308,7 +308,7 @@ test('ensure request instance is properly exposed to default values factory', (t const url = `${address}:${port}` return request('GET', url).then((response1) => { - t.assert.deepStrictEqual(response1.body.userId, 'http') + t.assert.strictEqual(response1.body.userId, 'http') }) }) }) @@ -328,10 +328,10 @@ test('does not throw when accessing context object outside of context', (t) => { const { address, port } = app.server.address() const url = `${address}:${port}` - t.assert.deepStrictEqual(app.requestContext.get('user'), undefined) + t.assert.strictEqual(app.requestContext.get('user'), undefined) return request('GET', url).then((response1) => { - t.assert.deepStrictEqual(response1.body.userId, 'system') + t.assert.strictEqual(response1.body.userId, 'system') }) }) }) @@ -351,7 +351,7 @@ test('passing a custom resource factory function when create as AsyncResource', const route = (req) => { const store = container.getStore(executionAsyncId()) - t.assert.deepStrictEqual(store.traceId, '1111-2222-3333') + t.assert.strictEqual(store.traceId, '1111-2222-3333') return Promise.resolve({ userId: req.requestContext.get('user').id }) } @@ -362,7 +362,33 @@ test('passing a custom resource factory function when create as AsyncResource', const url = `${address}:${port}` return request('GET', url).then((response1) => { - t.assert.deepStrictEqual(response1.body.userId, 'system') + t.assert.strictEqual(response1.body.userId, 'system') + }) + }) +}) + +test('returns the store', (t) => { + t.plan(2) + + app = fastify({ logger: true }) + app.register(fastifyRequestContext, { + defaultStoreValues: { foo: 42 }, + }) + + const route = (req) => { + const store = req.requestContext.getStore() + t.assert.strictEqual(store.foo, 42) + return store.foo + } + + app.get('/', route) + + return app.listen({ port: 0, host: '127.0.0.1' }).then(() => { + const { address, port } = app.server.address() + const url = `${address}:${port}` + + return request('GET', url).then((response1) => { + t.assert.strictEqual(response1.body, 42) }) }) }) diff --git a/types/index.d.ts b/types/index.d.ts index 82d130d..7b098a5 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -22,6 +22,7 @@ declare namespace fastifyRequestContext { export interface RequestContext { get(key: K): RequestContextData[K] | undefined set(key: K, value: RequestContextData[K]): void + getStore(): RequestContextData | undefined } export type CreateAsyncResourceFactory = (