NestJS Interceptor - Append data to incoming request Header or Body

Viewed 4004

I am trying to modify an NestJS incoming request and append some data either to header or Body. I was able to replace all the body data with my data but i would like to append and not remove the incoming body data.

Here is the code i have

export class MyInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    
    
    const token = request.headers['authorization'];
    if (token) {
      const decoded = jwt_decode(token);
      request.body['userId'] = decoded['id'];
    }

    return next.handle();
  }
}

Thanks in advance

2 Answers

I have added two examples as after running testing for the interceptor, it passed without any issue. Of course, my example will be very different to your set up, however, hopefully it'll give you enough insight:

The test file:


  test('should not mutate entire request body object', () => {
    const dto = {
      username: 'testuser',
      email: 'test@domain.com',
    };

    const headers = {
      authorization: 'Bearer sdkfjdsakfjdkjfdal',
    };

    return request(app.getHttpServer())
      .post('/')
      .send(dto)
      .set(headers)
      .expect(({ body }) => {
        expect(body.userId).toBeDefined();
        delete body.userId;

        expect(body).toStrictEqual(dto);
      });
  });

I understand your problem as attempting to obtain information about the authenticated user, and return it/use it later on? However, your current implementation seems to completely override the request.body instead of append your property to the original object.

Interceptor:



@Injectable()
export class HttpRequestBodyInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable {
    const request = context.switchToHttp().getRequest();
    const token = request.headers['authorization'];

    if (token) {
      // decode token
      request.body['userId'] = 'user_123456789';
    }

    return next.handle();
  }
}

Controller:


@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Post()
  @UseInterceptors(HttpRequestBodyInterceptor)
  getHello(@Req() req): string {
    return req.body;
  }
}

This returns the correct response and the test will pass. However, you may find a more robust solution would be:


@Injectable()
export class HttpRequestBodyInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable {
    const request = context.switchToHttp().getRequest();
    const token = request.headers['authorization'];

    if (token) {
      // decode token
      request.userId = 'user_123456789';
    }

    return next.handle();
  }
}

And then access this in your controller by:


@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Post()
  @UseInterceptors(HttpRequestBodyInterceptor)
  getHello(@Req() req) {
    return {
      userId: req.userId,
      ...req.body,
    };
  }
}

Finally, if your only need for an interceptor is to obtain that userId property, you may find that https://docs.nestjs.com/security/authentication#jwt-functionality is useful.

@Injectable()
 export class JwtInterceptor implements NestInterceptor {

 constructor(private readonly jwtService: JwtService, private readonly 
  userService: UserService) { }
 async intercept(context: ExecutionContext, next: CallHandler): 
  Promise<Observable<any>> {
  var request: WsArgumentsHost = context.switchToWs();
   var { handshake: { headers: { authorization } } } = 
    request.getClient();
try {
  var jwt = authorization.split(" ")[1];
  var { phone } = await this.jwtService.verify(jwt, jwtConstraints)
  var user: User = await this.userService.findUserByPhoneNumber(phone);
  
 
   request.getData()["user"]=user;
  return next.handle().pipe(map((data) => { return { ...data, 'user': "david" }; }));

i hope this will help someone in future while working with socket.i wanted the user object in the body after they pass authentication .the above trick worked out for me

Related