Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get handler route in NestJS Interceptor (For both Express and Fastify)

I am having issues trying to get a hold of the NestJS handler's route in an interceptor I am writing. For instance, if a Controller had a route as such:

  @Get('/params/:p1/:p2')
  routeWithParams(@Param() params): string {
    return `params are ${params.p1} and ${params.p2}`;
  }

I would like the ability to grab the value /param/:p1/:p2 programatically. Using the url and deparameterizing is NOT an option, as there is not really a way to do so in a %100 airtight manner. Did some digging and have not found a documented way to grab the route for the handler. Wondering if anyone else has had luck? Here is some example code I stripped down from my project:

import { Injectable, ExecutionContext, CallHandler, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { Request } from 'express';
import { FastifyRequest } from 'fastify';

function isExpressRequest(request: Request | FastifyRequest): request is Request {
  return (request as FastifyRequest).req === undefined;
}

@Injectable()
export class MyInterceptor implements NestInterceptor {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request: Request | FastifyRequest = context.switchToHttp().getRequest();

    if( !isExpressRequest(request) ) { // if req fufills the FastifyRequest interface, we will rename the transaction
      const req = request as FastifyRequest;
      const route = `` // TODO how can I grab the route either using the FastifyRequest or ExecutionContext??
    } // otherwise, we are in express request
    const route = `` // TODO how can I grab the route either using the Request or ExecutionContext?

    return next.handle();
  }
}

If it turns out that an interceptor won't do the trick and something else like a Guard could work to grab this information I'm all ears.

like image 829
SomeAnonGuy Avatar asked Mar 07 '20 07:03

SomeAnonGuy


People also ask

Is NestJS faster than express?

Fastify provides a good alternative framework for Nest because it solves design issues in a similar manner to Express. However, fastify is much faster than Express, achieving almost two times better benchmarks results. A fair question is why does Nest use Express as the default HTTP provider?

How do I add an interceptor to NestJS?

In order to set up the interceptor, we use the @UseInterceptors() decorator imported from the @nestjs/common package. Like pipes and guards, interceptors can be controller-scoped, method-scoped, or global-scoped. Hint The @UseInterceptors() decorator is imported from the @nestjs/common package.

What is interceptor in NestJS?

A NestJS Interceptor is basically a class annotated with the @Injectable() decorator. If you wish to know more about @Injectable() decorator, please refer to the detailed post on NestJS Providers. However, apart from the decorator, an interceptor should also implement the NestInterceptor interface.

Does NestJS use Express?

Finally, as we already mentioned, NestJS uses the Express framework by default as the request processing pipeline. This means if you are already familiar with Express processing, you'll be able to adapt your Express middleware to use within Nest.

How to bind a logginginterceptor in nestjs?

We can bind interceptors on various levels such as method, controller or even global. To bind an interceptor, we use the @UseInterceptor () decorator. Basically, the LoggingInterceptor will be applicable to this route handler in the controller. If you wish to know more about controllers, refer to the detailed post about NestJS Controllers.

How do I implement nest’s interceptors feature?

The simplest way to implement this feature would instead be using Nest.js Interceptors. If you come from the express world, you will be familiar with the idea of middleware. A middleware is essentially a function that receives a request and returns a response based on that request.

When to pass arguments to nestjs interceptors and guards?

We use NestJs interceptors and guards daily, and most often we do not need to wrap them into factories, but every once in a while we need to pass an argument statically to them when we decorate some controller or some controller’s method. Let’s say that we need to send some metrics, KPI, to track usage of our app.

What are RxJS interceptors and how do they work?

By using RxJs Observables, Interceptors allow you to inject logic into any point of the request life cycle. For a transaction interceptor, this is perfect because we need to both set up the transaction before the request is handled, and either commit it or roll it back depending on the success of the request.


1 Answers

After talking to the good folks on the NestJS Discord, I was pointed towards Reflectors. So, using a reflector I can actually fetch the path data passed into the HTTP method decorator.

import { Injectable, ExecutionContext, CallHandler, NestInterceptor } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable } from 'rxjs';
import { Request } from 'express';
import { FastifyRequest } from 'fastify';
import { PATH_METADATA } from '@nestjs/common/constants';

function isExpressRequest(request: Request | FastifyRequest): request is Request {
  return (request as FastifyRequest).req === undefined;
}

@Injectable()
export class MyInterceptor implements NestInterceptor {
  constructor(private readonly reflector: Reflector) {}

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request: Request | FastifyRequest = context.switchToHttp().getRequest();

    const path = this.reflector.get<string[]>(PATH_METADATA, context.getHandler()); 
    const method = isExpressRequest(request) ? request.method : (request as FastifyRequest).req.method;

    // can now do something with the path and method

    return next.handle();
  }
}

Now there is the valid concern that the PATH_METADATA key could move in NestJS common, breaking this code. Totally possible and something to look out for. But the fact that according to the git blame for the constants, the path key has not been updated for 3 years mollifies those concerns imo: https://github.com/nestjs/nest/blame/master/packages/common/constants.ts

like image 68
SomeAnonGuy Avatar answered Dec 31 '22 08:12

SomeAnonGuy