Skip to content

Commit

Permalink
feat: support hooks with payloads (#185)
Browse files Browse the repository at this point in the history
* support hooks with payloads

* reduce code duplication

* improve documentation
  • Loading branch information
Uzlopak committed May 14, 2023
1 parent b729a30 commit 87ef614
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 8 deletions.
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,20 @@ async function subsystem (fastify, opts) {
}
```

If you want to change the Fastify hook that the middleware will be attached to, pass a `hook` option like so:

*Note you can access `req.body` from the `preValidation` lifecycle step onwards. Take a look at the [Lifecycle](https://www.fastify.io/docs/latest/Reference/Lifecycle/) documentation page to see the order of the steps.*
It is possible to change the Fastify hook that the middleware will be attached to. Supported lifecycle hooks are:
- `onRequest`
- `preParsing`
- `preValidation`
- `preHandler`
- `preSerialization`
- `onSend`
- `onResponse`
- `onError`
- `onTimeout`

To change the hook, pass a `hook` option like so:

*Note you can access `req.body` from the `preParsing`, `onError`, `preSerialization` and `onSend` lifecycle steps. Take a look at the [Lifecycle](https://www.fastify.io/docs/latest/Reference/Lifecycle/) documentation page to see the order of the steps.*

```js
const fastify = require('fastify')()
Expand Down
41 changes: 38 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,46 @@
'use strict'

const fp = require('fastify-plugin')
const Middie = require('./engine')
const Middie = require('./lib/engine')
const kMiddlewares = Symbol('fastify-middie-middlewares')
const kMiddie = Symbol('fastify-middie-instance')
const kMiddieHasMiddlewares = Symbol('fastify-middie-has-middlewares')
const { FST_ERR_MIDDIE_INVALID_HOOK } = require('./lib/errors')

const supportedHooksWithPayload = [
'onError',
'onSend',
'preParsing',
'preSerialization'
]

const supportedHooksWithoutPayload = [
'onRequest',
'onResponse',
'onTimeout',
'preHandler',
'preValidation'
]

const supportedHooks = [...supportedHooksWithPayload, ...supportedHooksWithoutPayload]

function fastifyMiddie (fastify, options, next) {
fastify.decorate('use', use)
fastify[kMiddlewares] = []
fastify[kMiddieHasMiddlewares] = false
fastify[kMiddie] = Middie(onMiddieEnd)

const hook = options.hook || 'onRequest'

if (!supportedHooks.includes(hook)) {
next(new FST_ERR_MIDDIE_INVALID_HOOK(hook))
return
}

fastify
.addHook(options.hook || 'onRequest', runMiddie)
.addHook(hook, supportedHooksWithPayload.includes(hook)
? runMiddieWithPayload
: runMiddie)
.addHook('onRegister', onRegister)

function use (path, fn) {
Expand All @@ -25,11 +54,12 @@ function fastifyMiddie (fastify, options, next) {
} else {
this[kMiddie].use(path, fn)
}
this[kMiddieHasMiddlewares] = true
return this
}

function runMiddie (req, reply, next) {
if (this[kMiddlewares].length > 0) {
if (this[kMiddieHasMiddlewares]) {
req.raw.originalUrl = req.raw.url
req.raw.id = req.id
req.raw.hostname = req.hostname
Expand All @@ -46,6 +76,10 @@ function fastifyMiddie (fastify, options, next) {
}
}

function runMiddieWithPayload (req, reply, _payload, next) {
runMiddie.bind(this)(req, reply, next)
}

function onMiddieEnd (err, req, res, next) {
next(err)
}
Expand All @@ -54,6 +88,7 @@ function fastifyMiddie (fastify, options, next) {
const middlewares = instance[kMiddlewares].slice()
instance[kMiddlewares] = []
instance[kMiddie] = Middie(onMiddieEnd)
instance[kMiddieHasMiddlewares] = false
instance.decorate('use', use)
for (const middleware of middlewares) {
instance.use(...middleware)
Expand Down
File renamed without changes.
7 changes: 7 additions & 0 deletions lib/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use strict'

const { createError } = require('@fastify/error')

const FST_ERR_MIDDIE_INVALID_HOOK = createError('FST_ERR_MIDDIE_INVALID_HOOK', 'The %s-hook is not supported by @fastify/middie', 500)

module.exports.FST_ERR_MIDDIE_INVALID_HOOK = FST_ERR_MIDDIE_INVALID_HOOK
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"tsd": "^0.28.0"
},
"dependencies": {
"@fastify/error": "^3.2.0",
"fastify-plugin": "^4.0.0",
"path-to-regexp": "^6.1.0",
"reusify": "^1.0.4"
Expand Down
135 changes: 134 additions & 1 deletion test/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const sget = require('simple-get').concat
const cors = require('cors')

const middiePlugin = require('../index')
const { FST_ERR_MIDDIE_INVALID_HOOK } = require('../lib/errors')

test('Should support connect style middlewares', t => {
t.plan(4)
Expand Down Expand Up @@ -626,7 +627,9 @@ test('Should support plugin level prefix', t => {
})
})

test('register the middleware at a different hook', async t => {
test('register the middleware at preHandler hook', async t => {
t.plan(2)

const fastify = Fastify()
t.teardown(fastify.close)

Expand All @@ -653,3 +656,133 @@ test('register the middleware at a different hook', async t => {
const res = await fastify.inject('/')
t.same(res.json(), { hello: 'world' })
})

test('register the middleware at preParsing hook', async t => {
t.plan(2)

const fastify = Fastify()
t.teardown(fastify.close)

let onRequestCalled = false

await fastify.register(middiePlugin, {
hook: 'preParsing'
})

fastify.use(function (req, res, next) {
t.ok(onRequestCalled)
next()
})

fastify.addHook('onRequest', function (req, reply, next) {
onRequestCalled = true
next()
})

fastify.get('/', async (req, reply) => {
return { hello: 'world' }
})

const res = await fastify.inject('/')
t.same(res.json(), { hello: 'world' })
})

test('register the middleware at preValidation hook', async t => {
t.plan(2)

const fastify = Fastify()
t.teardown(fastify.close)

let onRequestCalled = false

await fastify.register(middiePlugin, {
hook: 'preValidation'
})

fastify.use(function (req, res, next) {
t.ok(onRequestCalled)
next()
})

fastify.addHook('onRequest', function (req, reply, next) {
onRequestCalled = true
next()
})

fastify.get('/', async (req, reply) => {
return { hello: 'world' }
})

const res = await fastify.inject('/')
t.same(res.json(), { hello: 'world' })
})

test('register the middleware at preSerialization hook', async t => {
t.plan(2)

const fastify = Fastify()
t.teardown(fastify.close)

let onRequestCalled = false

await fastify.register(middiePlugin, {
hook: 'preSerialization'
})

fastify.use(function (req, res, next) {
t.ok(onRequestCalled)
next()
})

fastify.addHook('onRequest', function (req, reply, next) {
onRequestCalled = true
next()
})

fastify.get('/', async (req, reply) => {
return { hello: 'world' }
})

const res = await fastify.inject('/')
t.same(res.json(), { hello: 'world' })
})

test('register the middleware at onSend hook', async t => {
t.plan(2)

const fastify = Fastify()
t.teardown(fastify.close)

let onRequestCalled = false

await fastify.register(middiePlugin, {
hook: 'onSend'
})

fastify.use(function (req, res, next) {
t.ok(onRequestCalled)
next()
})

fastify.addHook('onRequest', function (req, reply, next) {
onRequestCalled = true
next()
})

fastify.get('/', async (req, reply) => {
return { hello: 'world' }
})

const res = await fastify.inject('/')
t.same(res.json(), { hello: 'world' })
})

test('throw error when registering middie at onRequestAborted hook', async t => {
const fastify = Fastify()
t.teardown(fastify.close)

t.rejects(() => fastify.register(middiePlugin, {
hook: 'onRequestAborted'
}), new FST_ERR_MIDDIE_INVALID_HOOK('onRequestAborted')
)
})
2 changes: 1 addition & 1 deletion test/engine.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const middie = require('../engine')
const middie = require('../lib/engine')
const t = require('tap')
const http = require('http')
const { join } = require('path')
Expand Down

0 comments on commit 87ef614

Please sign in to comment.