Search code examples
imageuploadnestjs

Nestjs Image Validation


I have created an endpoint to upload an avatar and the controller is like this :

  @Post('/avatar')
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './public/avatars',
        filename: (req, file, cb) => {
          const { user } = req as unknown as { user: typeof ReqUser };
          const { id } = user as unknown as { id: string };

          const filename: string = id;
          const extension: string = path.parse(file.originalname).ext;
          cb(null, `${filename}${extension}`);
        },
      }),
    }),
  )
  async uploadAvatar(
    @UploadedFile(
      new ParseFilePipe({
        validators: [
          new MaxFileSizeValidator({ maxSize: 5000000 }),
          new FileTypeValidator({ fileType: /image\/(jpeg|png|jpg)/ }),
        ],
      }),
    )
    file: Express.Multer.File,
    @ReqUser() user,
  ) {
    return this.meService.setAvatar(file, user);
  }

The problem Im facing is that if the file isnt valid, the corresponding error will be thrown but the file will be uploaded on the server, for example it should only allow image upload with .jpg,png,jpg extention, but the file will be be uploaded anyway? what am i doing wrong in this case?


Solution

  • Just like @jaymcdoniel explained, the interceptor will run before the code executes your uploadAvatar function.

    To stop uploading the file to your server's storage, you could use fileFilter option in Multer.

    @Post('/avatar')
    @UseInterceptors(
      FileInterceptor('file', {
        fileFilter: (req, file, cb) => {
          // Write your condition below based on the mimetype and/or filename extension.
          if (<YOUR_CONDITION_TO_REJECT_THE_FILE>) {
            cb(null, false);
          } else {
            cb(null, true);
          }
        },
        storage: diskStorage({
          destination: './public/avatars',
          filename: (req, file, cb) => {
            const { user } = req as unknown as { user: typeof ReqUser };
            const { id } = user as unknown as { id: string };
    
            const filename: string = id;
            const extension: string = path.parse(file.originalname).ext;
            cb(null, `${filename}${extension}`);
          },
        }),
      })
    )
    async uploadAvatar(
      ...
    

    This will prevent Multer from saving the file inside your sever at first. This way, you will not need to handle deleting the file incase the file is of wrong type.