dmitriy-nz / nestjs-form-data

NestJS middleware for handling multipart/form-data, which is primarily used for uploading files.
https://www.npmjs.com/package/nestjs-form-data
MIT License
117 stars 23 forks source link

In version 1.8.3 mimetype is undefined #40

Open salos1982 opened 1 year ago

salos1982 commented 1 year ago

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

dmitriy-nz commented 1 year ago

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

salos1982 commented 1 year ago

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 {


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 commented 1 year ago

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

salos1982 commented 1 year ago

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

dmitriy-nz commented 1 year ago

@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.

berhir commented 4 hours ago

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.