'Intercepting in Multer Mutates Request? (NestJS)

Does multer mutates any request that has given to it? I'm currently trying to intercept the request to add this in logs.

But whenever I try to execute this code first:

        const newReq = cloneDeep(request); // lodash cloneDeep
        const newRes = cloneDeep(response); 
        const postMulterRequest: any = await new Promise((resolve, reject) => {
          const multerReponse = multer().any()
    
          multerReponse(request, newRes, err => {
            if (err) reject(err)
            resolve(request)
          })
        })
        files = postMulterRequest?.files;

The @UseInterceptors(FileInterceptor('file')) becomes undefined.

I have already seen the problem, it seems like the multerReponse(request, newRes, err => { mutates the request. But I don't know what the other approach I can do to fix this. (I tried JSON Serialization, Object.assign, cloneDeep, but none of those worked)

I have tried adding newReq and newRes (cloned object) to multerResponse at first it worked. But at the second time, the thread only hangs up, and doesn't proceed to next steps. Or the multerReponse(request, newRes, err => { doesn't return anything.

The whole code looks like this and used globally (some parts of here were redacted/removed; but the main logic is still the same) :

@Injectable()
export class AuditingInterceptor implements NestInterceptor {
  constructor(
    @InjectModel(Auditing.name)
    private readonly AuditingModel: Model<Auditing>,
  ) {}

  async intercept(
    context: ExecutionContext,
    next: CallHandler,
  ): Promise<Observable<any>> {
    const request = context.switchToHttp().getRequest();
    const response = context.switchToHttp().getResponse();
    const { headers, method, ip, route, query, body } = request;
    let bodyParam = Object.assign({}, body),
      files: any;
    const newReq = cloneDeep(request); // lodash cloneDeep
    const newRes = cloneDeep(response);
    const postMulterRequest: any = await new Promise((resolve, reject) => {
      const multerReponse = multer().any();
      multerReponse(newReq, newRes, (err) => {
        if (err) reject(err);
        resolve(newReq);
      });
    });
    files = postMulterRequest?.files;

    return next.handle().pipe(
      tap(() =>
        this.AuditingModel.create({
          request: {
            query,
            bodyParam,
            files,
          },
          timeAccessed: new Date().toISOString(),
        }),
      ),
    );
  }
}

Summary of what I need to do here is I need to intercept and log the file in our DB before it gets processed in the method/endpoint that uses @UseInterceptors(FileInterceptor('file')).



Solution 1:[1]

I have solve this by intercepting the request using the

@Req() req

and creating a method to handle the files that was intercepted inside the FileInterceptor decorator.

Code Example:

// create logs service first to handle your queries
createLogs(file, req){
   // do what you need to do with the file, and req here
   const { filename } = file;
   const { ip } = req
   ....

}


// main service
   // inject the service first

constructor(@Inject(LogsService) private logsService: LogsService)
uploadHandler(file, req){
   this.logsService.createLogs(file, req)
   // proceed with the next steps
   .... 
}

// controller
@Post('upload')
@UseInterceptors(FileInterceptor('file'))
testFunction(@UploadedFile() file: Express.Multer.File,, @Req req){
    return this.serviceNameHere.uploadHandler(file, req);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 xsephtion