Skip to content

feat(common): add pipes for multiple files validation #14994

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

kitihounel
Copy link

@kitihounel kitihounel commented Apr 20, 2025

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

What is the current behavior?

When dealing with file uploads, NestJS offers the ParseFilePipe to help validate files uploaded under the same name. But when several files are uploaded with different names, there is not built-in pipe available and the validation is usually done in the controller method or service.

@Post('upload')
@UseInterceptors(
  FileFieldsInterceptor([
    { name: 'avatar', maxCount: 1 },
    { name: 'background', maxCount: 1 },
  ])
)
uploadFile(
  @UploadedFiles()
  files: { avatar?: Express.Multer.File[], background?: Express.Multer.File[] }
) {
  const { avatar, background } = files;
  // Files are validated here...
}

Issue Number: N/A

What is the new behavior?

This PR adds two new pipes, ParseFileFieldsPipe and GroupFilesPipe that can be used to validate multiple files together in association with the UploadedFiles decorator and file interceptors.

Here are some examples:

@Controller('uploads')
export class UploadsController {
  @Post()
  @UseInterceptors(
    FileFieldsInterceptor([
      { name: 'avatar', maxCount: 1 },
      { name: 'documents', maxCount: 2 },
    ]),
  )
  upload(
    @UploadedFiles(
      new ParseFileFieldsPipe({
        fields: [
          {
            name: 'documents',
            options: {
              fileIsRequired: false,
              validators: [
                new FileTypeValidator({ fileType: 'application/pdf' }),
              ],
            },
          },
          {
            name: 'avatar',
            options: {
              validators: [
                new FileTypeValidator({ fileType: /.(jpeg|png)$/ }),
              ],
            },
          },
        ],
      })
    )
    files,
  ) {
    console.log('Received:', files);

    return 'Hi!';
  }
}

The ParseFileFieldsPipe constructor accepts an options object with a fields prop that defines for each uploaded file, the validation options that will passed to the ParseFilePipe object that will be used for validation.

It is also possible to validate files extracted with AnyFilesInterceptor() by using GroupFilesPipe and ParseFileFieldsPipe together:

@Post()
  @UseInterceptors(
    AnyFilesInterceptor(),
  )
  upload(
    @UploadedFiles(
      new GroupFilesPipe(),
      new ParseFileFieldsPipe({
        fields: [
          {
            name: 'documents',
            options: {
              validators: [
                new FileTypeValidator({ fileType: /.(zip|png)$/ }),
              ],
            }
          },
          {
            name: 'avatar'
            options: {
              validators: [
                new FileTypeValidator({ fileType: /.(jpeg|png)$/ }),
              ],
            },
          },
        ],
      })
    )
    files,
  ) {
    console.log('Received:', files);

    return 'Hi!';
  }
}

The GroupFilesPipe is used to group uploaded files by fieldname, like the FileFieldsInterceptor does.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

If the PR is accepted, the NestJS doc about file uploads will be updated to integrate the new features.

When dealing with file uploads, NestJS offers the `ParseFilePipe` to help validate files uploaded under the same name. But when several files are uploaded with different names, there is not built-in pipe available and the validation is usually done in the controller method or service. This commit add two new pipes, `ParseFileFieldsPipe` and `GroupFilesPipe` that can be used two validate multiple files together in association with the `UploadedFiles` decorator and `FileValidator`.
@coveralls
Copy link

Pull Request Test Coverage Report for Build 0f9b6c20-02ec-4f86-accd-ac87f432d4ca

Details

  • 40 of 40 (100.0%) changed or added relevant lines in 3 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.07%) to 89.387%

Totals Coverage Status
Change from base Build 600c1ebc-e7f1-48f2-bb00-a8366dddbcf8: 0.07%
Covered Lines: 7201
Relevant Lines: 8056

💛 - Coveralls

@kamilmysliwiec
Copy link
Member

Given how much trouble the current validators have caused, I'm seriously thinking about dropping them in future releases.

This really feels like something that should live in its own package anyway—no need to keep it under @nestjs/common or maintain it there

@nestjs nestjs locked and limited conversation to collaborators Apr 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants