@fastify/middie
@fastify/middie is the plugin that adds middleware support on steroids to Fastify.
The syntax style is the same as express/connect.
Does not support the full syntax middleware(err, req, res, next)
, because error handling is done inside Fastify.
Install
npm i @fastify/middie
Usage
Register the plugin and start using your middleware.
const Fastify = require('fastify')
async function build () {
const fastify = Fastify()
await fastify.register(require('@fastify/middie'), {
hook: 'onRequest' // default
})
// do you know we also have cors support?
// https://github.com/fastify/fastify-cors
fastify.use(require('cors')())
return fastify
}
build()
.then(fastify => fastify.listen({ port: 3000 }))
.catch(console.log)
Encapsulation support
The encapsulation works as usual with Fastify, you can register the plugin in a subsystem and your code will work only inside there, or you can declare the middie plugin top level and register a middleware in a nested plugin, and the middleware will be executed only for the nested routes of the specific plugin.
Register the plugin in its own subsystem:
const fastify = require('fastify')()
fastify.register(subsystem)
async function subsystem (fastify, opts) {
await fastify.register(require('@fastify/middie'))
fastify.use(require('cors')())
}
Register a middleware in a specific plugin:
const fastify = require('fastify')()
fastify
.register(require('@fastify/middie'))
.register(subsystem)
async function subsystem (fastify, opts) {
fastify.use(require('cors')())
}
Hooks and middleware
Every registered middleware will be run during the onRequest
hook phase, so the registration order is important.
Take a look at the Lifecycle documentation page to understand better how every request is executed.
const fastify = require('fastify')()
fastify
.register(require('@fastify/middie'))
.register(subsystem)
async function subsystem (fastify, opts) {
fastify.addHook('onRequest', async (req, reply) => {
console.log('first')
})
fastify.use((req, res, next) => {
console.log('second')
next()
})
fastify.addHook('onRequest', async (req, reply) => {
console.log('third')
})
}
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 documentation page to see the order of the steps.
const fastify = require('fastify')()
fastify
.register(require('@fastify/middie'), { hook: 'preHandler' })
.register(subsystem)
async function subsystem (fastify, opts) {
fastify.addHook('onRequest', async (req, reply) => {
console.log('first')
})
fastify.use((req, res, next) => {
console.log('third')
next()
})
fastify.addHook('onRequest', async (req, reply) => {
console.log('second')
})
fastify.addHook('preHandler', async (req, reply) => {
console.log('fourth')
})
}
Restrict middleware execution to a certain path(s)
If you need to run a middleware only under certain path(s), just pass the path as first parameter to use and you are done!
const fastify = require('fastify')()
const path = require('path')
const serveStatic = require('serve-static')
fastify
.register(require('@fastify/middie'))
.register(subsystem)
async function subsystem (fastify, opts) {
// Single path
fastify.use('/css', serveStatic(path.join(__dirname, '/assets')))
// Wildcard path
fastify.use('/css/*', serveStatic(path.join(__dirname, '/assets')))
// Multiple paths
fastify.use(['/css', '/js'], serveStatic(path.join(__dirname, '/assets')))
}
Middie Engine
You can also use the engine itself without the Fastify plugin system.
Usage
const Middie = require('@fastify/middie/engine')
const http = require('http')
const helmet = require('helmet')
const cors = require('cors')
const middie = Middie(_runMiddlewares)
middie.use(helmet())
middie.use(cors())
http
.createServer(function handler (req, res) {
middie.run(req, res)
})
.listen(3000)
function _runMiddlewares (err, req, res) {
if (err) {
console.log(err)
res.end(err)
return
}
// => routing function
}
Keep the context
If you need it you can also keep the context of the calling function by calling run
with run(req, res, this)
, in this way you can avoid closures allocation.
http
.createServer(function handler (req, res) {
middie.run(req, res, { context: 'object' })
})
.listen(3000)
function _runMiddlewares (err, req, res, ctx) {
if (err) {
console.log(err)
res.end(err)
return
}
console.log(ctx)
}
Restrict middleware execution to a certain path(s)
If you need to run a middleware only under certains path(s), just pass the path as first parameter to use
and you are done!
Note that this does support routes with parameters, e.g. /user/:id/comments
, but all the matched parameters will be discarded
// Single path
middie.use('/public', staticFiles('/assets'))
// Multiple middleware
middie.use('/public', [cors(), staticFiles('/assets')])
// Multiple paths
middie.use(['/public', '/dist'], staticFiles('/assets'))
// Multiple paths and multiple middleware
middie.use(['/public', '/dist'], [cors(), staticFiles('/assets')])
To guarantee compatibility with Express, adding a prefix uses path-to-regexp
to compute
a RegExp
, which is then used to math every request: it is significantly slower.
TypeScript support
To use this module with TypeScript, make sure to install @types/connect
.
Middleware alternatives
Fastify offers some alternatives to the most commonly used Express middleware:
Express Middleware | Fastify Plugin |
---|---|
helmet |
fastify-helmet |
cors |
fastify-cors |
serve-static |
fastify-static |
Acknowledgements
This project is kindly sponsored by:
Past sponsors:
License
Licensed under MIT.