Fastify Fundamentals: A Quick Guide to  Plugins and Encapsulation with Platformatic

Fastify Fundamentals: A Quick Guide to Plugins and Encapsulation with Platformatic

Fastify enables developers to build complex Node.js applications and specify exactly how they want their applications to perform.

This is made possible through the use of various plugins. The fastify-plugin utility helps developers publish hooks and decorators on the same parent instance; thereby avoiding encapsulation.

We recently held a Masterclass exploring this in detail. To view the full masterclass, check it out below:

In this article, we will explore the plugin capabilities of Fastify, and how to use this natively with Platformatic.

Use Cases of Plugins and Encapsulations in Fastify

A plugin is a software extension that can be added to enhance the functionality or capability of an application. For instance, there is a Fastify/MongoDB plugin that helps Node.js developers manage their database with MongoDB while using Fastify.

Fastify encourages reusability via the use of plugins. Virtually anything can be wrapped within a plugin, which provides encapsulation so that its decorators and hooks are limited to the defined routes.

Fastify allows you to write an entry-point and provides two plugins.

An example of how to use a plugin is shown below. Below, we can also see that we can use the plugin with a prefix.

import fastify from 'fastify'
import myPlugin from './plugin.js'

const app = fastify({ logger: true })

app.register(import('./plugin.js')) // root
app.register(myPlugin, { prefix: '/my-plugin' })
app.register(async function anotherPlugin (app) {
  app.get('/inline-plugin', async (request, reply) => {
    return { hello: 'world' }
  })
})

await app.listen({ port: 3000 })

Encapsulation limits the decoration to the child plugin tree. If we take a look at the code below, we can see that hooks are specified in the context. This is one of the key Fastify features that enables the utility of the module.

import fastify from 'fastify'

const app = fastify({ logger: true })

app.decorateRequest('answer', 42)

app.register(async function publicContext (app) {
  app.decorateRequest('foo')
  app.get('/one', myRoute)
  app.addHook('onRequest', async (request) => {
    request.foo = 'foo'
  })
  app.register(grandChildContext)
})

async function grandChildContext (app) {
  app.decorateRequest('bar')
  app.addHook('onRequest', async (request) => {
    request.foo = 'foo1'
    request.bar = 'bar'
  })
  app.get('/two', myRoute)
}

grandChildContext[Symbol.for('skip-override')] = true

async function myRoute (request, response) {
  return { answer: request.answer, foo: request.foo, bar: request.bar }
}

app.listen({ port: 3000 })

Break Encapsulation

Fastify allows developers to avoid encapsulation by using the fastify-plugin utility. In this way, hooks and decorators are published on the parent instance as well.

From the image above, Plugin 2 is working in the context of the entry point.

Plugins Provide Separation

Plugins provide separation, hence it is possible to write an application in sub-apps. Each of those sub-apps will also be completely encapsulated by each other, as illustrated below:

Recommended Project Structure

In this structure, we group all the logic that is shared between multiple routes and then create a Routes folder with a nested structure.

File-System-Based Routing

This system refers to a specific approach for defining your application's routes based on the organization of files and folders within your project directory. Fastify has a module that helps handle this seamlessly: the @fastify/autoload package.

Autoload supports file-system-based routing by default. It allows developers to place files in a folder, which would work by default.

To use @fastify/autoload, first install the package by running the command below:

npm i @fastify/autoload

Then, edit the app.js file to configure the autoload and stop loading the plugins and routes manually as shown below.

import fastifyAutoload from '@fastify/autoload';


//Then enable it by editing the register function as shown below

//Remove this line
// app.register(app);

app.register(fastifyAutoload, {
dir: `${import.meta.dirname}/plugins`,
encapsulate: false  //This is to specify to break encapsulation on the plugin utility
}

app.register(fastifyAutoload, {
dir: `${import.meta.dirname}/routes`
}

Wrapping Up

In this article, you have solidified your understanding of the capabilities of Fastify plugins, and how you can use them in your Node.js applications.

Supercharging Fastify Development with Platformatic

Developed by the co-creator of Fastify, Platformatic is a backend development platform designed to extend the capabilities of the Fastify web framework. Together, Platformatic and Fastify offer:

  • Developer-centric design

  • Real-time metrics

  • A vast plugin ecosystem

  • Built-in validation and serialization

  • Built-in logging

Find out more and get in touch.