Search code examples
typescriptfile-uploadnestjsmulter

Nestjs Uploading a file using @UploadedFile decorator : how to make the parameter non-mandatory?


With Nest.js, I am trying to code a create (Post) route for an ingredient in my meal-planner app. The route would take in, as a request body, a description (optional) and a name (mandatory), as well as an optional image. I am using Objection.js as an ORM.

I read the Nest.js documentation for File Uploading Nest.js File Upload handling with Multer and tried to do it the same way as in the docs. The problem is, I can't find anywhere how to use the UploadedFile decorator while making the file optional. I receive the following error message when I try to create a new ingredient without an image via Postman :

{
    "statusCode": 400,
    "message": "File is required",
    "error": "Bad Request"
}

Did someone ever stumble on this problem here and found out a solution to make the parameter optional? I know I could create a Patch route to modify the ingredient and add an image to it after as a workaround, but I would like to know if there is anything I could do while keeping the actual.

This is the code of my Controller :

@Post()
  @UseInterceptors(
    FileInterceptor('image', {
      storage: diskStorage({
        destination: './assets/images/ingredient',
        filename: getUniqueFileName,
      }),
    }),
  )
  @UseFilters(DeleteFileOnErrorFilter)
  async create(
    @Body() dto: CreateIngredientDto,
    @UploadedFile(
      new ParseFilePipe({
        validators: [new FileTypeValidator({ fileType: '.(png|jpeg|jpg)' })],
      }),
    )
    image?: Express.Multer.File,
  ): Promise<IngredientModel> {
    return this.ingredientService.create(dto, image);
  }

And the create method called from the Service :

async create(
    dto: CreateIngredientDto,
    image?: Express.Multer.File,
  ): Promise<IngredientModel> {
    try {
      return await ImageModel.transaction(async () => {
        if (image) {
          const imagePath = await ImageModel.query().insert({
            location: image.path,
          });
          return this.modelClass
            .query()
            .insert({ ...dto, imageId: imagePath.id });
        }
        return this.modelClass.query().insert({ ...dto });
      });
    } catch (err) {
      this.logger.error('An error occurred while creating the ingredient');
      return null;
    }
  }

Solution

  • You can pass fileIsRequired as false to the ParseFilePipe class.

    @UploadedFile(
      new ParseFilePipe({
        validators: [new FileTypeValidator({ fileType: '.(png|jpeg|jpg)' })],
        fileIsRequired: false,
      }),
    )