nestjs-form-data icon indicating copy to clipboard operation
nestjs-form-data copied to clipboard

In version 1.8.3 mimetype is undefined

Open salos1982 opened this issue 2 years ago • 6 comments

I'm trying to upload a video using such a structure

export class VideoUploadData {
  @IsFile()
  @MaxFileSize(10 * 1024 * 1204)
  @ApiProperty()
  file: MemoryStoredFile;
  @ApiProperty()
  fieldName: string;
}

In version 1.7.1 file.mimetype contained a mime type of video, But in version 1.8.3 it is undefined. I see busBoyMimeType property but it is protected

salos1982 avatar Nov 10 '22 16:11 salos1982

In version 1.8.3, the mime-type logic was changed, but new getters were added to support older versions. Please post a log of the uploaded file from your dto, and make sure you use the class-transformer in your module

Check StoredFile source for details

dmitriy-nz avatar Nov 19 '22 20:11 dmitriy-nz

Now I have issue with validating mimetypes for svg. This is upload data

  @IsFile()
  @MaxFileSize(5 * 1024 * 1024)
  @HasMimeType(['image/jpeg', 'image/png', 'image/webp', 'image/svg+xml'])
  @ApiProperty()
  file: MemoryStoredFile;
  @ApiProperty()
  blockConfigId?: string;
  @ApiProperty()
  blockName?: string;
  @ApiProperty()
  fieldName: string;
  @ApiProperty()
  subdir?: string;
}```
Controller

@ApiTags('Files') @Post('sites/:siteId/uploadImage') @FormDataRequest() async uploadImage( @Param('siteId') siteId: string, @Body() imageData: ImageUploadData, @CurrentUser() user: User, ): Promise<ImageConfigData> {

And I got folowing error when I upload svg file
```[
  ValidationError {
    target: ImageUploadData {
      fieldName: 'items.1.image',
      blockConfigId: '623ad511a119d8e1e26b5419',
      blockName: 'Banner on Home Page',
      file: [MemoryStoredFile]
    },
    value: MemoryStoredFile {
      originalName: 'logoQwHvA.svg',
      encoding: '7bit',
      busBoyMimeType: 'image/svg+xml',
      buffer: <Buffer 3c 3f 78 6d 6c 20 76 65 72 73 69 6f 6e 3d 22 31 2e 30 22 20 65 6e 63 6f 64 69 6e 67 3d 22 55 54 46 2d 38 22 20 73 74 61 6e 64 61 6c 6f 6e 65 3d 22 6e ... 11515 more bytes>,
      size: 11565,
      fileType: [Object]
    },
    property: 'file',
    children: [],
    constraints: {
      HasMimeType: 'File must be of one of the types image/jpeg, image/png, image/webp, image/svg+xml'
    }
  }
]```

When I upload jpg or png file everything is ok

salos1982 avatar Mar 15 '23 16:03 salos1982

Issue is in file-type dependency. It is not reliable source of mime type. It replaces correct with possible but wrong.

salos1982 avatar Mar 16 '23 08:03 salos1982

Also On the latest nest.js it seems that all geberated properties are omited then I use decorator Body(). So I have no mimeType property at all

salos1982 avatar Mar 16 '23 08:03 salos1982

@salos1982 Hi! file-type library which is used to determine mime-type is not suitable for text-based file formats, as it requires parsing the file. From the file-type readme:

This package is for detecting binary-based file formats, not text-based formats like .txt, .csv, .svg, etc.

You can use @HasExtension to check by file extension or write your own validator, e.g. based on https://www.npmjs.com/package/is-svg.

dmitriy-nz avatar May 19 '23 18:05 dmitriy-nz

I had the same issue and debugged my code. It turned out that my DTO was not an instance of the DTO class. Instead, it was a plain JS object. That's the reason the getters of the StoredFile class were missing because getters get not serialized.

To solve my issue, I had to transform the payload objects:

@UsePipes(new ValidationPipe({ transform: true }))

Now my DTOs are class instances and the StoredFile is also an instance with all the getters available.

berhir avatar Aug 27 '24 14:08 berhir