lukeautry / tsoa

Build OpenAPI-compliant REST APIs using TypeScript and Node
MIT License
3.33k stars 481 forks source link

Can't Handle File and Non-File Field on multipart/form-data simultaneously #1584

Closed shibukazu closed 4 months ago

shibukazu commented 4 months ago

Sorting

Expected Behavior

The following code is an example of a post endpoint handler:

public async postHandler(
  @FormField("userId") userId: string,
  @UploadedFile("file1") file1: Express.Multer.File,
  @UploadedFile("file2") file2: Express.Multer.File
  ): Promise<Response> {}

The expected behavior is that this handler can handle multipart/form-data requests correctly.

Current Behavior

Currently, it outputs an error message like the following:

{
    "message": "Cannot read properties of undefined (reading 'length')"
}

Possible Solution

This issue seems to be caused by an incorrect implementation of the template engine, specifically expressTemplateService.ts line 84. The current implementation treats all fields in formData as files if any file is included in the multipart/form-data request. As a result, it fails to handle non-file fields correctly.

case 'formData': {
    const files = Object.values(args).filter(param => param.dataType === 'file');
    if (files.length > 0) {
        const requestFiles = request.files;
        const fileArgs = this.validationService.ValidateParam(param, requestFiles[name], name, fieldErrors, undefined, this.minimalSwaggerConfig);
        return fileArgs.length === 1 ? fileArgs[0] : fileArgs;
    }
    else if (param.dataType === 'array' && param.array && param.array.dataType === 'file') {
        return this.validationService.ValidateParam(param, request.files, name, fieldErrors, undefined, this.minimalSwaggerConfig);
    }
    else {
        return this.validationService.ValidateParam(param, request.body[name], name, fieldErrors, undefined, this.minimalSwaggerConfig);
    }
}

To address this issue, the code should be modified as follows:

case 'formData': {
    if (param.dataType === 'file') {
        const files = Object.values(args).filter(param => param.dataType === 'file');
        if (files.length > 0) {
            const requestFiles = request.files;
            const fileArgs = this.validationService.ValidateParam(param, requestFiles[name], name, fieldErrors, undefined, this.minimalSwaggerConfig);
            return fileArgs.length === 1 ? fileArgs[0] : fileArgs;
        }
    }
    else if (param.dataType === 'array' && param.array && param.array.dataType === 'file') {
        return this.validationService.ValidateParam(param, request.files, name, fieldErrors, undefined, this.minimalSwaggerConfig);
    }
    else {
        return this.validationService.ValidateParam(param, request.body[name], name, fieldErrors, undefined, this.minimalSwaggerConfig);
    }
}

May I publish pull request for this issue?

Context (Environment)

Version of the library: 6.1.3 Version of NodeJS: 18

github-actions[bot] commented 4 months ago

Hello there shibukazu 👋

Thank you for opening your very first issue in this project.

We will try to get back to you as soon as we can.👀

WoH commented 4 months ago

https://github.com/lukeautry/tsoa/pull/1583

WoH commented 4 months ago

https://github.com/lukeautry/tsoa/releases/tag/v6.1.4

shibukazu commented 4 months ago

I'm sorry for bothering you, thanks!