Skip to content

Commit

Permalink
Add requestIdFactory option (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabriel-pinheiro committed Oct 2, 2020
1 parent 3aad851 commit b451571
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 10 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ These are the available config options for the middleware/plugin functions. All
// Request header name, case insensitive (default: 'X-Request-Id').
// Used if useHeader is set to true.
headerName: 'X-Request-Id',
// A custom function to generate your request ids. Defaults to UUID v1.
// Ignored if useHeader is set to true.
requestIdFactory: () => 'Your request id',
// Use request id generated by Fastify instead of generating a new id.
// Only available for the Fastify plugin.
useFastifyRequestId: false
Expand Down
6 changes: 6 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { IncomingMessage, ServerResponse } from 'http'

export type RequestIdFactory = () => unknown

export interface IOptions {
// Default: false
useHeader?: boolean
// Default: 'X-Request-Id'
headerName?: string
// Default: UUID v1
requestIdFactory?: RequestIdFactory
}

export interface IFastifyOptions {
Expand All @@ -14,6 +18,8 @@ export interface IFastifyOptions {
headerName?: string
// Default: false
useFastifyRequestId?: boolean
// Default: UUID v1
requestIdFactory?: RequestIdFactory
}

export interface IHapiPlugin<T> {
Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
{
"name": "Andrey Goncharov",
"url": "https://github.com/aigoncharov"
},
{
"name": "Gabriel Pinheiro",
"url": "https://github.com/gabriel-pinheiro"
}
],
"license": "MIT",
Expand Down
33 changes: 23 additions & 10 deletions src/rtracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,20 @@ const wrapHttpEmitters = (req, res) => {
* (default: `false`)
* @param {string} options.headerName request header name, used if `useHeader` is set to `true`
* (default: `X-Request-Id`)
* @param {function} options.requestIdFactory function used to generate request ids
* (default: UUIDs v1)
*/
const expressMiddleware = ({
useHeader = false,
headerName = 'X-Request-Id'
headerName = 'X-Request-Id',
requestIdFactory = uuidv1
} = {}) => {
return (req, res, next) => {
let requestId
if (useHeader) {
requestId = req.headers[headerName.toLowerCase()]
}
requestId = requestId || uuidv1()
requestId = requestId || requestIdFactory()

als.run(requestId, () => {
wrapHttpEmitters(req, res)
Expand All @@ -51,12 +54,15 @@ const expressMiddleware = ({
* (default: `X-Request-Id`)
* @param {boolean} options.useFastifyRequestId respect Fastify request id flag
* (default: `false`)
* @param {function} options.requestIdFactory function used to generate request ids
* (default: UUIDs v1)
*/
const fastifyPlugin = (fastify, options, next) => {
const {
useHeader = false,
headerName = 'X-Request-Id',
useFastifyRequestId = false
useFastifyRequestId = false,
requestIdFactory = uuidv1
} = options

fastify.addHook('onRequest', (request, reply, done) => {
Expand All @@ -67,7 +73,7 @@ const fastifyPlugin = (fastify, options, next) => {
if (useFastifyRequestId) {
requestId = requestId || request.id
}
requestId = requestId || uuidv1()
requestId = requestId || requestIdFactory()

als.run(requestId, () => {
wrapHttpEmitters(request.raw, reply.raw || reply.res)
Expand All @@ -88,17 +94,20 @@ fastifyPlugin[Symbol.for('fastify.display-name')] = pluginName
* (default: `false`)
* @param {string} options.headerName request header name, used if `useHeader` is set to `true`
* (default: `X-Request-Id`)
* @param {function} options.requestIdFactory function used to generate request ids
* (default: UUIDs v1)
*/
const koaMiddleware = ({
useHeader = false,
headerName = 'X-Request-Id'
headerName = 'X-Request-Id',
requestIdFactory = uuidv1
} = {}) => {
return (ctx, next) => {
let requestId
if (useHeader) {
requestId = ctx.request.headers[headerName.toLowerCase()]
}
requestId = requestId || uuidv1()
requestId = requestId || requestIdFactory()

return als.run(requestId, () => {
wrapHttpEmitters(ctx.req, ctx.res)
Expand All @@ -115,17 +124,20 @@ const koaMiddleware = ({
* (default: `false`)
* @param {string} options.headerName request header name, used if `useHeader` is set to `true`
* (default: `X-Request-Id`)
* @param {function} options.requestIdFactory function used to generate request ids
* (default: UUIDs v1)
*/
const koaV1Middleware = ({
useHeader = false,
headerName = 'X-Request-Id'
headerName = 'X-Request-Id',
requestIdFactory = uuidv1
} = {}) => {
return function * (next) {
let requestId
if (useHeader) {
requestId = this.request.headers[headerName.toLowerCase()]
}
requestId = requestId || uuidv1()
requestId = requestId || requestIdFactory()

als.enterWith(requestId)
try {
Expand All @@ -148,15 +160,16 @@ const hapiPlugin = ({
register: async (server, options) => {
const {
useHeader = false,
headerName = 'X-Request-Id'
headerName = 'X-Request-Id',
requestIdFactory = uuidv1
} = options

server.ext('onRequest', (request, h) => {
let requestId
if (useHeader) {
requestId = request.headers[headerName.toLowerCase()]
}
requestId = requestId || uuidv1()
requestId = requestId || requestIdFactory()
als.enterWith(requestId)
wrapHttpEmitters(request.raw.req, request.raw.res)

Expand Down
20 changes: 20 additions & 0 deletions tests/express.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ describe('cls-rtracer for Express', () => {
request(app).get('/test').catch(done)
})

test('uses request id factory when provided', () => {
const app = express()
const idFactory = () => 'generated-id'

app.use(rTracer.expressMiddleware({
requestIdFactory: idFactory
}))

app.get('/test', (req, res) => {
const id = rTracer.id()
res.json({ id })
})

return request(app).get('/test')
.then(res => {
expect(res.statusCode).toBe(200)
expect(res.body.id).toEqual(idFactory())
})
})

test('ignores header by default', () => {
const app = express()
app.use(rTracer.expressMiddleware())
Expand Down
20 changes: 20 additions & 0 deletions tests/fastify.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ describe('cls-rtracer for Fastify', () => {
app.ready().then(() => request(app.server).get('/test')).catch(done)
})

test('uses request id factory when provided', () => {
const app = Fastify()
const idFactory = () => 'generated-id'

app.register(rTracer.fastifyPlugin, {
requestIdFactory: idFactory
})

app.get('/test', async (_, reply) => {
const id = rTracer.id()
reply.send({ id })
})

return app.ready().then(() => request(app.server).get('/test'))
.then(res => {
expect(res.statusCode).toBe(200)
expect(res.body.id).toEqual(idFactory())
})
})

test('ignores header by default', () => {
const app = Fastify()
app.register(rTracer.fastifyPlugin)
Expand Down
19 changes: 19 additions & 0 deletions tests/fastifyv2.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ for (const type of types) {
app.ready().then(() => request(app.server).get('/test')).catch(done)
})

test('uses request id factory when provided', () => {
const app = Fastify()
const idFactory = () => 'generated-id'
register(type, app, {
requestIdFactory: idFactory
})

app.get('/test', async (_, reply) => {
const id = rTracer.id()
reply.send({ id })
})

return app.ready().then(() => request(app.server).get('/test'))
.then(res => {
expect(res.statusCode).toBe(200)
expect(res.body.id).toEqual(idFactory())
})
})

test('ignores header by default', () => {
const app = Fastify()
register(type, app)
Expand Down
22 changes: 22 additions & 0 deletions tests/hapi.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,28 @@ describe('cls-rtracer for Hapi', () => {
}).catch(done)
})

test('uses request id factory when provided', async () => {
const idFactory = () => 'generated-id'

server = await setupServer({
options: {
requestIdFactory: idFactory
},
handler: () => {
const id = rTracer.id()
return { id }
}
})

const res = await server.inject({
method: 'get',
url: '/'
})

expect(res.statusCode).toBe(200)
expect(res.result.id).toEqual(idFactory())
})

test('ignores header by default', async () => {
const idInHead = 'id-from-header'
let id
Expand Down
20 changes: 20 additions & 0 deletions tests/koa.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ describe('cls-rtracer for Koa', () => {
request(app.callback()).get('/').catch(done)
})

test('uses request id factory when provided', () => {
const app = new Koa()
const idFactory = () => 'generated-id'

app.use(rTracer.koaMiddleware({
requestIdFactory: idFactory
}))

app.use((ctx) => {
const id = rTracer.id()
ctx.body = { id }
})

return request(app.callback()).get('/')
.then(res => {
expect(res.statusCode).toBe(200)
expect(res.body.id).toEqual(idFactory())
})
})

test('ignores header by default', () => {
const app = new Koa()
app.use(rTracer.koaMiddleware())
Expand Down
19 changes: 19 additions & 0 deletions tests/koav1.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,25 @@ describe('cls-rtracer for Koa v1', () => {
request(app.callback()).get('/').catch(done)
})

test('uses request id factory when provided', () => {
const app = new Koa()
const idFactory = () => 'generated-id'
app.use(rTracer.koaV1Middleware({
requestIdFactory: idFactory
}))

app.use(function * () {
const id = rTracer.id()
this.body = { id }
})

return request(app.callback()).get('/')
.then(res => {
expect(res.statusCode).toBe(200)
expect(res.body.id).toEqual(idFactory())
})
})

test('ignores header by default', () => {
const app = new Koa()
app.use(rTracer.koaV1Middleware())
Expand Down

0 comments on commit b451571

Please sign in to comment.