Search code examples
imagevalidationnestjsmultipart-upload

In NestJS 10, how do I set my FileValidator to only accept image uploads?


I'm using NestJS 10. I want to create a file upload endpoint that only accepts image file uploads. I created

  @Post()
  @UseInterceptors(
    FileFieldsInterceptor([
      { name: 'frontImg', maxCount: 1 },
      { name: 'backImg', maxCount: 1 },
    ]),
  )
  async create(
    @Req() req: Request,
    @Body('title') title: string,
    @Body('frontImgAltText') frontImgAltText: string,
    @Body('category') category: Occasion,
    @UploadedFiles(
      new ParseFilePipe({
        validators: [
          new FileTypeValidator({ fileType: /(jpg|jpeg|png|webp)$/ }),
        ],
      }),
    )
    files: { frontImg: Express.Multer.File[]; backImg?: Express.Multer.File[] },
  ) { ... }

but when I execute a request against the endpoint, it consistently fails with the error

{
    "message": "Validation failed (expected type is /(jpg|jpeg|png|webp)$/)",
    "error": "Bad Request",
    "statusCode": 400
}

What's the proper way to create a validator that only accepts certain image file types?


Solution

  • The issue here is that when isValid method from the built-in FileTypeValidator is called it gets an object with the two fields frontImg and backImg: enter image description here and it makes sense since files is defined like that here:

     files: { frontImg: Express.Multer.File[]; backImg?: Express.Multer.File[] }
    

    and it doesn't have any mimetype whatsoever.

    I think one way to work around this can be to create a small pipe that forwards every file to FileTypeValidator like this:

        @UseInterceptors(
        FileFieldsInterceptor([
          { name: 'frontImg', maxCount: 1 },
          { name: 'backImg', maxCount: 1 },
        ]),
      )
      async uploadTest(
        @UploadedFiles({
          transform: (fileRequest: {
            frontImg: Express.Multer.File[];
            backImg?: Express.Multer.File[];
          }) => {
            const validator = new FileTypeValidator({
              fileType: /(jpg|jpeg|png|webp)$/,
            });
            if (
              validator.isValid(fileRequest.frontImg[0]) &&
              validator.isValid(fileRequest.backImg[0])
            ) {
              return fileRequest;
            }
    
            throw new HttpException(validator.buildErrorMessage(), 400);
          },
        })
        files: {
          frontImg: Express.Multer.File[];
          backImg?: Express.Multer.File[];
        },
      ) {
        console.log(files);
      }