Implement the fastifySession Middleware within NestJS by incorporating it into the MiddlewareConsumer within the AppModule

I have a Nestjs application running with Fastify. My goal is to implement the fastifySession middleware using the MiddlewareConsumer in Nestjs. Typically, the configuration looks like this:

configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(
        fastifySession,
      )
      .forRoutes({
        path: '*',
        method: RequestMethod.ALL,
      });
  }
}

The issue here is that the fastifySession middleware requires an options object. In a regular Fastify app, it would be set up using the register method as follows:

app.register(fastifySession, {
   secret: '',
   cookie: {
     secure: false,
     domain: 'localhost',
   },
  store: new SessionStore(new SessionService()),
});

Instead of using the register method directly in main.ts, I want to leverage the Nestjs dependency injection by applying the middleware in the AppModule. Is there a way to achieve this?

UPDATE

I had the idea to create a custom Nestjs middleware to handle the registration of required Fastify plugins.

This is the middleware I developed:


@Injectable()
class FastifySession implements NestMiddleware {
  private options;
  private fastifyPassport;

  constructor(
    private adapterHost: HttpAdapterHost,
    private sessionStore: SessionStore,
    private userService: UserService,
  ) {
    this.fastifyPassport = new Authenticator();

    this.options = {
      cookie: {
        secure: false,
        maxAge: 50000,
        path: '/',
        httpOnly: true,
        sameSite: false,
        domain: 'localhost',
      },
      store: this.sessionStore,
    };
  }

  use(req: any, res: any, next: (error?: any) => void) {
    const httpAdapter = this.adapterHost.httpAdapter;
    const instance = httpAdapter.getInstance();

    instance.register(fastifyCookie);
    instance.register(fastifySession, this.options);

    instance.register(this.fastifyPassport.initialize());
    instance.register(this.fastifyPassport.secureSession());

    this.fastifyPassport.registerUserSerializer(async (user: User, request) => {
      console.log(user.id);
      return user.id;
    });

    this.fastifyPassport.registerUserDeserializer(async (id, request) => {
      const user = await this.userService.getUser(+id);
      console.log('user ', user);
      return user;
    });

    next();
  }
}

I added the created middleware to my AppModule

export class AppModule implements NestModule {
  constructor() {
  }

  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(FastifySession)
      .forRoutes({
        path: '*',
        method: RequestMethod.ALL,
      });
  }
}

However, I encountered this error

ERROR [ExceptionsHandler] Root plugin has already booted
AvvioError: Root plugin has already booted

During my investigation, I came across this GitHub Issue

https://github.com/nestjs/nest/issues/1462

As per the insights in the GitHub issue, it seems registering Fastify plugins outside main.ts may not be feasible.

I would greatly appreciate any assistance or guidance in resolving this challenge!

Answer №1

To include a plugin within a module, I would utilize the onModuleInit method along with a module that injects the HttpAdapterHost. Here is an example implementation:

@Module(moduleMetadata)
export class AppModule implements OnMoudleInit {
  constructor(private readonly httpAdapterHost: HttpAdapterHost) {}

  async onModuleInit() {
    const adapterInstance = this.httpAdapterHost.httpAdapter.getInstance();
    await adapterInstance.register(fastifySession, fastifySessionOptions)
  }
}

By following this approach, the adapter will register the middleware during application startup, preventing inadvertent multiple registrations on each route call (avoiding redundant calls to instance.register() as seen in the original code snippet)

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

TS7053: The element is implicitly assigned an 'any' type as the expression of type 'string' cannot be used to index the type '{ username: string; email: string; '

Having trouble incorporating TypeScript into a custom React Form Component, and I keep encountering an error that I can't seem to resolve. Error message TS7053: Element implicitly has an 'any' type because expression of type 'string&apo ...

The art of neatly bundling a Typescript external module at the highest level

I'm currently working on a TypeScript NPM package, where I have organized all the classes and interfaces. However, upon review, it seems that my approach is repetitive and not very clean, especially with the empty class and interface extensions. I am ...

Error encountered when initializing a variable within the constructor of a TypeScript file in Angular 4

This is the content of my app.component.html file PL Auth Username: Password : Generate OTP Enter OTP : Login This is the code in my app.component.ts file import { Component, OnInit } from '@angular/core' ...

Here is a unique version: "Dealing with Node.js ES6 (ESM) Modules in TypeScript can be tricky, especially when the TypeScript Compiler (TSC) fails to emit the

I am facing an issue while transpiling my TypeScript project to JavaScript. I have set the project to resolve as an ES6 Module (ESM) by using the "module":"ES6" configuration, but the problem persists. This is the current setup in my ...

Angular 4's Mddialog experiencing intermittent display problem

While using MDDialog in my Angular app, I've encountered a couple of issues. Whenever a user clicks on the div, flickering occurs. Additionally, if the user then clicks on one of the buttons, the afterclose event is not triggered. Can anyone provide ...

Dealing with throwing Exceptions in jest: A guide for developers

I have developed a method that throws an exception when the provided password does not match a regex pattern. I attempted to handle this in Jest. it('Should prevent insertion of a new user if the password doesn't match the regex', async () ...

Snackbar and RTK Query update trigger the error message: "Warning: Cannot update during an existing state transition."

I've built a basic ToDos application that communicates with a NodeJS backend using RTK Query to fetch data, update state, and store cache. Everything is functioning properly as expected with the communication between the frontend and backend. Recently ...

Limit users to entering either numbers or letters in the input field

How can I enforce a specific sequence for user input, restricting the first two characters to alphabets, the next two to numbers, the following two to characters, and the last four to numbers? I need to maintain the correct format of an Indian vehicle regi ...

Having trouble with implementing Spotify OAuth in NextJS?

I am in the process of creating a music website portfolio using Spotify and NextJS. I want to incorporate music playback on the website, but I am encountering issues with Spotify authentication. When I click the login button, I receive a 405 HTTP status er ...

Alerts in Angular templates of inherited class in WebStorm

While working with WebStorm 2019.3.2, I have noticed some warnings in Angular templates: https://example.com/image.png This is happening because the properties are being initialized on the parent component instead of the child. @Component({ selector: ...

Having trouble getting a local npm installation to work from a specific file path?

After following the instructions from this helpful link to install an npm package through a file path, I encountered an error when attempting to use it: Cannot find module '<module_name>' or its corresponding type declaration Are there an ...

In the domain of React and Typescript, a minimum of '3' arguments is anticipated; nonetheless, the JSX factory 'React.createElement' is only equipped with a maximum of '2' arguments. This incongruity is signaled by the

I am facing an error with this particular component: const TheBarTitle = ( theClass: any, columnTitle: string, onClickAction: any, ) => { return ( <div className={theClass} title="Click to add this ...

An error occurred due to attempting to access properties of null while trying to read 'useMemo' in a Next.js TypeScript application

Currently engaged in a Next.js 13 project with TypeScript, utilizing the useDrag hook. No errors are being flagged in my Visual Studio Code editor; however, upon attempting to render the page, an error message surfaces. The issue points to a problem with t ...

Tips for iterating over an array that implements either of two interfaces in TypeScript

The objective is to develop a reusable method for filtering out items from an array that implements one of two interfaces Providing a code example would be most helpful: interface IDuration { start: number; end: number; } interface IRelativeDuration ...

Using TypeScript to specify data types in the Vue data object

I am currently utilizing Vue.js with Typescript in a webpack project. Following the guidelines provided in the Recommended Configuration in my tsconfig.json, I have set: "strict": true, Within one of my components, I have: declare interface P ...

Why is the table not sorting when I apply filters?

I am encountering an issue where the data filters and table sorting are not working together. When I apply filters, the sorting functionality stops working. The filters work fine independently, but once applied, they interfere with the sorting feature. Any ...

What is the process for transitioning global reusable types to package types within turborepo?

When creating an app within the apps folder, a global.d.ts file is required with specific types defined like this: interface Window{ analytics: any; } This file should be designed to be reusable and placed in the packages/types directory for easy acce ...

Struggling with verifying the visibility of multiple elements using the toBeVisible() assertion

While running a test in debug mode, I've observed that toBeVisible() fails when it detects multiple elements. Interestingly, toBeVisible without the parenthesis passes the assertion in such cases. I'm facing a specific scenario where I need to p ...

Guide on sending JSON object to Angular custom components

I have implemented a custom element in Angular 7 using the CUSTOM_ELEMENTS_SCHEMA. My app.module.ts code is as follows: export class AppModule { constructor(private injector: Injector) {} ngDoBootstrap() { this.registerCustomElements( ...

Utilize Typescript to expand the functionality of the Express Request object

Is there a way to add a custom property to the request object in Express middleware using TypeScript without resorting to bracket notation? I am struggling to find a solution that satisfies this requirement. I would ideally like to achieve something like ...