Skip to content

Commit

Permalink
feat: expose getStore() (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
Eomm authored Mar 2, 2025
1 parent 150564a commit 0244b63
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 22 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const requestContext = {
store[key] = value
}
},
getStore: () => {
return asyncLocalStorage.getStore()
},
}

function fastifyRequestContext(fastify, opts, next) {
Expand Down
68 changes: 47 additions & 21 deletions test-tap/requestContextPlugin.e2e.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand Down Expand Up @@ -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')

Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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')

Expand All @@ -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)
})
})
})
Expand All @@ -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)
Expand Down Expand Up @@ -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')
})
})
})
Expand Down Expand Up @@ -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')
})
})
})
Expand All @@ -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')
})
})
})
Expand All @@ -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')
})
})
})
Expand All @@ -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 })
}

Expand All @@ -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)
})
})
})
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ declare namespace fastifyRequestContext {
export interface RequestContext {
get<K extends keyof RequestContextData>(key: K): RequestContextData[K] | undefined
set<K extends keyof RequestContextData>(key: K, value: RequestContextData[K]): void
getStore(): RequestContextData | undefined
}

export type CreateAsyncResourceFactory<T extends AsyncResource = AsyncResource> = (
Expand Down

0 comments on commit 0244b63

Please sign in to comment.