Fastify plugins
Tags: fastify, node, webdev
Published: 2021-06-26 23:07:59

- [Why plugins?](#why-plugins)
- [What does a plugin look like?](#what-does-a-plugin-look-like)
- [Encapsulation](#encapsulation)
- [How to access registered plugins from route handlers?](#how-to-access-registered-plugins-from-route-handlers)

## <a name="why-plugins"></a>Why plugins?
Fastify let you to plug ( inject ) your dependencies to Fastify instance and then use them wherever you have access to the instance throughout you app. And if you decide to migrate from a monolithic structure to microservices later on, it helps you with that, because every plugin could be a service itself.

## <a name="what-does-a-plugin-look-like"></a>What does a plugin look like?
A plugin is just a function that takes in `fastify` and `options` as inputs.<br>
This is a plugin:
```js
function pluginA(fastify, options, done) {
	// ...
	done()
}
```
and this is an async plugin:
```js
async function pluginB(fastify, options) {
	// ...
}
```
and here is how to register them:
```js
import Fastify from 'fastify'

const fastify = Fastify()

fastify
	.register(pluginA)
	.register(pluginB)
```

## <a name="encapsulation"></a>Encapsulation
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 ) that instance would only be accessible inside the plugin.
<p align="center">
	<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srfw39xya0qxbnak2pld.png" alt="Fastify plugins with encapsulation" />
</p>
```js
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.
<p align="center">
	<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zhxurf0qxiongtjb3tgv.png" alt="Fastify plugins without encapsulation" />
</p>
```js
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`.<br>
Here is the simplified version of [fastify-postgres](https://github.com/fastify/fastify-postgres) plugin:
```js
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)
```

## <a name="how-to-access-registered-plugins-from-route-handlers"></a>How to access registered plugins from route handlers?
Here I used PostgresSQL. I want to be able to use it inside my route handlers to send queries to the database:
```js
// 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:
```js
// 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.<br>
> NOTE: Normal functions must be used rather than arrow functions to define route handlers. Read more [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#arrow_functions_used_as_methods).
```js
// routes.js

import { mainHandler } from './handlers.js'

export default function routes(fastify, options, done) {
	fastify.route({
		method: 'GET',
		url: '/',
		handler: mainHandler
	})

	done()
}
```
```js
// handlers.js

export function mainHandler(req, reply) {
	// Have access to this.pg here
}
```

## End
I recommend you to read the [docs](https://fastify.dev/docs/latest/Reference/Plugins) if you still have questions about Fastify plugins. You can also join [Fastify discord channel](https://discord.gg/fastify), there is a fantastic community there that can help you out.