39
Fastify plugin system
Let's say I need to send queries to the database from different modules of my app. Should I connect to db, export the connection, and then import it in all modules where I need to use it? Well, it works but it results in a spaghetti code. This is where Fastify plugin system comes in handy. It let's you to plug ( inject ) your dependencies to Fastify instance and then you can use them wherever you have access to the instance. It also helps you to move from a monolithic structure to microservices easily, because every service can be a plugin itself.
A plugin is just a function that takes in fastify
and options
as inputs.
This is how a plugin looks like:
function pluginA(fastify, options, done) {
// ...
done()
}
and this is how an async plugin looks like:
async function pluginB(fastify, options) {
// ...
}
and here is how to register them:
import Fastify from 'fastify'
const fastify = Fastify()
fastify
.register(pluginA)
.register(pluginB)
What encapsulation means is that a copy of Fastify instance is passed to the plugin when you register it. So anything you add to ( decorate ) Fastify instance would only be accessible inside the plugin.
import Fastify from 'fastify'
const fastify = Fastify()
fastify
.register(function pluginA(fastify, options, done) {
// Add a random number to fastify instance
fastify.decorate('rand', Math.random())
console.log(fastify.rand) // Accessible here
done()
})
.register(function pluginB(fastify, options, done) {
// Try to access the random number added in pluginA
console.log(fastify.rand) // undefined
done()
})
What if you don't want encapsulation? You can use fastify-plugin
package to register a plugin to the main Fastify instance.
import Fastify from 'fastify'
import fp from 'fastify-plugin'
const fastify = Fastify()
fastify
// Register pluginA with fastify-plugin
.register(fp(function pluginA(fastify, options, done) {
// Add a random number to fastify instance
fastify.decorate('rand', Math.random())
console.log(fastify.rand) // Accessible here
done()
}))
.register(function pluginB(fastify, options, done) {
// Try to access the random number added in pluginA
console.log(fastify.rand) // Also accessible here
done()
})
Packages like fastify-postgres
, fastify-mongodb
, fastify-redis
, ... they all use fastify-plugin
so you won't have to register them with fastify-plugin
.
Here is the simplified version of fastify-postgres plugin:
const pg = require('pg')
const fp = require('fastify-plugin')
function fastifyPostgres(fastify, options, next) {
const pool = new pg.Pool(options)
const db = {
connect: pool.connect.bind(pool),
pool: pool,
Client: pg.Client,
query: pool.query.bind(pool),
transact: transact.bind(pool)
}
// Inject postgres connection to Fastify instance
fastify.decorate('pg', db)
next()
}
module.exports = fp(fastifyPostgres)
Here I used PostgresSQL as the database of my app. I want to be able to use it inside my route handlers to send queries to the database:
// index.js
import Fastify from 'fastify'
import pg from 'fastify-postgres'
import routes from './routes.js'
const fastify = Fastify()
fastify
.register(pg, {
connectionString: 'postgres://postgres@localhost/postgres'
})
.register(routes)
Here I defined route handlers inside a plugin, so I can access fastify.pg
there:
// routes.js
export default function routes(fastify, options, done) {
fastify.route({
method: 'GET',
url: '/',
handler: (req, reply) => {
// Have access to fastify.pg here
}
})
done()
}
Here I defined route handlers in a seperate module, so in order to access fastify
I need to use the this
keyword.
NOTE: Normal functions must be used rather than arrow functions to define route handlers. Read more here.
// routes.js
import { mainHandler } from './handlers.js'
export default function routes(fastify, options, done) {
fastify.route({
method: 'GET',
url: '/',
handler: mainHandler
})
done()
}
// handlers.js
export function mainHandler(req, reply) {
// Have access to this.pg here
}
I recommend you to read the docs if you still have questions about Fastify plugins. You can also join Fastify discord channel, there is a fantastic community there that can help you out.
39