What makes fastify-plugin better than simply calling a regular function?

I recently came across a detailed explanation of how fastify-plugin operates and its functionality. Despite understanding the concept, I am left with a lingering question; what sets it apart from a standard function call without using the .register() method?

For further clarification, how do the following two approaches differ:

const app = fastify();

// Register a fastify-plugin that decorates app
const myPlugin = fp((app: FastifyInstance) => {
  app.decorate('example', 10);
});
app.register(myPlugin);

// Directly decorate the app
const decorateApp = (app: FastifyInstance) => {
  app.decorate('example', 10);
};
decorateApp(app);

Answer №1

When you create a decorateApp function, you are essentially designing your own way to load your application - like having your own custom "API". However, one of the initial challenges you will encounter is deciding between handling it synchronously or asynchronously:

  • The sync function is decorateApp
  • The async function is decorateAppAsync within another async function

For instance, you might need to fetch data from a database before initializing your application.

const decorateApp = (app) => {
  app.register(require('@fastify/mongodb'))
};

const businessLogic = async (app) => {
  const data = await app.mongo.db.collection('data').find({}).toArray()
}

decorateApp(app)
businessLogic(app) // Oops: this part is asynchronous

In such scenarios, several code changes are required:

  • The decorateApp function must now be made async
  • The mongodb registration should be awaited
  • The core application loading code needs to be asynchronous as well

Alternatively, by following fastify's approach, only the database-loading plugin needs adjustment:

const applicationConfigPlugin = fp(
+  async function (fastify) {
-  function (fastify, opts, next) {
-    app.register(require('@fastify/mongodb'))
-    next()
+    await app.register(require('@fastify/mongodb'))
  }
)

Note that the example in fastify-plugin code does not include next callback since it's a synchronous function.

An additional issue to lookout for is high hidden coupling among functions. Each application requires a configuration. Normally, the fastify instance is enriched with it.

Hence, you may find:

decorateAppWithConfig(app);
decorateAppWithSomethingElse(app);

In this case, decorateAppWithSomethingElse must realize that it is loaded after decorateAppWithConfig. With fastify-plugin on board, you can simplify this process:

const applicationConfigPlugin = fp(
  async function (fastify) {
    fastify.decorate('config', 42);
  },
  {
    name: 'my-app-config',
  }
)

const applicationBusinessLogic = fp(
  async function (fastify) {
     // ...
  },
  {
    name: 'my-app-business-logic',
    dependencies: ['my-app-config']
  }
)

// Incorrect order of applying plugins would now throw a clear error message:
app.register(applicationBusinessLogic);
app.register(applicationConfigPlugin);

This setup ensures better error handling and management of dependencies compared to manually structuring each function to work with fastify instances. The built-in validation checks provided by fastify-plugin streamline these processes effectively.

While the example in question may seem straightforward, scaling up to larger applications can introduce complexity due to various factors like synchronicity, error messaging, and dependency management intricacies.

  • Varying loading mechanisms (sync/async)
  • Inadequate error feedback
  • Implicit dependencies causing confusion

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Iterating through JSON objects in JavaScript using 'Foreach'

After receiving a JSON Object from my PHP script, I am trying to extract specific data using JavaScript. { "Data":{ "Recipes":{ "Recipe_7":{ "ID":"7", "TITLE":"Wu ...

Angular 2 Encounter Error When Trying to Access Undefined Property in a Function

Element: import { Component, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; @Component({ selector: 'app-ore-table', templateUrl: './ore-table.component.html', styleUrls: [&a ...

Issue: function is not a valid type (during mount)

Currently, I'm trying to add a feature that automatically closes all menus and modals when a user clicks outside of the specified area. Although I am successfully calling this.closeMenu(), an error is occurring stating that this.closeMenu is not reco ...

Changing namespaces or module containers that share the same name can result in a clash

Trying to reorganize some code that was mistakenly namespaced and move it to its own namespace without affecting the current functionality during the process. The original code is structured as follows: // (org) module General.Admin.Dialogs { export cl ...

Is there a way to determine the present date within a template?

In my component, I am working with an object that contains a timestamp. What I aim to achieve is to dynamically check this timestamp in the template at runtime. For instance, I want to display the online status of a member by showing a green dot if they a ...

I encountered a "ReferenceError: db is not defined" while trying to call a function in Express.js with MongoDB intergr

The structure of the code is as follows: var express = require('express'); var router = express.Router(); var mongo = require('mongodb').MongoClient; function getData(){ db.collection("collection_name").find({}).toArray(function (er ...

What is the best way to capture videos using Safari?

Hey there! I've set up the browser camera on my website for users to record live tests. It's been working great on Chrome and Firefox using MediaRecorder, but unfortunately, Safari isn't cooperating. Does anyone know of an alternative to Me ...

Can you explain the significance of the "type" reserved word in TypeScript?

When attempting to construct an interface in TypeScript, I discovered that the word "type" is both a keyword and a reserved term. In Visual Studio 2013 with TypeScript 1.4, for instance, when defining the following interface: interface IExampleInterface { ...

There appears to be an issue with Javascript's ability to handle JSON API requests

I'm currently working on a webpage that utilizes the openweathermap API to showcase the user's city and local temperature. Unfortunately, I'm encountering an issue where the JSON API is not being processed and nothing is happening. Despite r ...

Creating a structure within a stencil web component

In my current project, I am utilizing Stencil.js (typescript) and need to integrate this selectbox. Below is the code snippet: import { Component, h, JSX, Prop, Element } from '@stencil/core'; import Selectr from 'mobius1-selectr'; @ ...

How to style text in CSS with a numbered underline beneath

Is there a way to apply underlining to text and include a small number underneath the underline in a similar style shown in this image, by utilizing css, html, or javascript? ...

Extracting information from an external website in the form of XML data

Trying to retrieve data from an XML feed on a remote website , I encountered issues parsing the XML content and kept receiving errors. Surprisingly, fetching JSON data from the same source at worked perfectly. The code snippet used for XML parsing is as f ...

Why isn't it possible to send POST data to a JSON file using JQuery/AJAX?

I'm currently learning how to use JQuery/Ajax from a helpful tutorial on YouTube. To watch the video, simply click here. While I can successfully retrieve data from the order.json file, I encounter an error whenever trying to send POST requests. Bel ...

The deno bundle operation failed due to the absence of the 'getIterator' property on the type 'ReadableStream<R>'

When attempting to run deno with bundle, an error is encountered: error: TS2339 [ERROR]: Property 'getIterator' does not exist on type 'ReadableStream<R>'. return res.readable.getIterator(); ~~~~~~~~~~~ ...

The `Required<Partial<Inner>>` does not inherit from `Inner`

I stumbled upon a code snippet that looks like this: type Inner = { a: string } type Foo<I extends Inner> = { f: I } interface Bar<I extends Inner> { b: I } type O<I extends Partial<Inner>> = Foo<Required<I>> & B ...

Issues with passing information from a child component to a parent component in a

Currently, I am developing a guessing game that involves questions and selection logic embedded in a component known as Questions. However, I am facing issues with App not being able to read the Questions code correctly. My objective is to have the state i ...

Establishing a connection pathway for communication among components in Angular

I am faced with a situation where I have two components, CompA and CompA5, that are 3 or 4 levels apart. I need to establish a means of communication between these components. For instance, I want component CompA to send an event to CompA5, receive some d ...

Using a loop to chain jQuery's .when().then() method and ensuring a fixed final call at the end of the

The solution that closely matches my issue can be found at One common use case for .then is chaining ajax requests: $.ajax({...}).then(function(){ return $.ajax({...}); }).then(function(){ return $.ajax({...}); }).then(function(){ retu ...

Node.js: Changing binary information into a readable string

I'm faced with a challenge - the code I wrote seems to be returning data in binary format. How can I convert this into a string? fs.readFile('C:/test.prn', function (err, data) { bufferString = data.toString(); bufferStringSplit = buff ...

Ways to verify if the inner <div> contains any text

I am attempting to determine if the inner <div> contains the text "Ended" and then remove it if it does. There are multiple <div> elements with the same class. I have attempted to use the .filter() method. My goal is to remove the container_one ...