【问题标题】:How do I annotate an endpoint in NestJS for OpenAPI that takes Multipart Form Data如何在 NestJS 中为采用多部分表单数据的 OpenAPI 注释端点
【发布时间】:2021-03-12 22:03:26
【问题描述】:

我的 NestJS 服务器有一个接受文件和其他表单数据的端点 例如,我在表单中传递了一个文件和文件创建者的 user_id。

需要明确告知 NestJS Swagger 正文包含文件并且端点使用 multipart/form-data 这在 NestJS 文档 https://docs.nestjs.com/openapi/types-and-parameters#types-and-parameters 中没有记录。

【问题讨论】:

    标签: file-upload swagger nestjs openapi nestjs-swagger


    【解决方案1】:

    这是我发现的更清洁的方法:

    @Injectable()
    class FileToBodyInterceptor implements NestInterceptor {
      intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const ctx = context.switchToHttp();
        const req = ctx.getRequest();
        if(req.body && req.file?.fieldname) {
          const { fieldname } = req.file;
          if(!req.body[fieldname]) {
            req.body[fieldname] = req.file;
          }
        }
    
        return next
          .handle();
      }
    }
    
    const ApiFile = (options?: ApiPropertyOptions): PropertyDecorator => (
      target: Object, propertyKey: string | symbol
    ) => {
      ApiProperty({
        type: 'file',
        properties: {
          [propertyKey]: {
            type: 'string',
            format: 'binary',
          },
        },
      })(target, propertyKey);
    };
    
    class UserImageDTO {
      @ApiFile()
      file: Express.Multer.File;  // you can name it something else like image or photo
      
      @ApiProperty()
      user_id: string;
    }
    
    
    @Controller('users')
    export class UsersController {
    
      @ApiBody({ type: UserImageDTO })
      // @ApiResponse( { type: ... } ) // some dto to annotate the response
      @Post('files')
      @ApiConsumes('multipart/form-data')
      @UseInterceptors(
        FileInterceptor('file'),  //this should match the file property name
        FileToBodyInterceptor,  // this is to inject the file into the body object
      ) 
      async addFile(@Body() userImage: UserImageDTO): Promise<void> { // if you return something to the client put it here
        console.log({modelImage}); // all the fields and the file
        console.log(userImage.file); // the file is here
    
        // ... your logic
      }
    }
    
    

    FileToBodyInterceptorApiFile 是通用的,我希望它们在 NestJs 中的位置

    您可能需要安装@types/multer 才能拥有Express.Multer.File

    【讨论】:

      【解决方案2】:

      幸运的是,一些错误引发了有关如何处理此用例的讨论

      看看这两个讨论 https://github.com/nestjs/swagger/issues/167 https://github.com/nestjs/swagger/issues/417 我能够将以下内容放在一起

      我使用 DTO 添加了注释: 两个关键部分是:

      在 DTO 中添加

        @ApiProperty({
          type: 'file',
          properties: {
            file: {
              type: 'string',
              format: 'binary',
            },
          },
        })
        public readonly file: any;
      
        @IsString()
        public readonly user_id: string;
      

      在控制器中添加

      @ApiConsumes('multipart/form-data')
      

      这让我有一个工作端点

      还有这个 OpenAPI Json

      {
         "/users/files":{
            "post":{
               "operationId":"UsersController_addPrivateFile",
               "summary":"...",
               "parameters":[
                  
               ],
               "requestBody":{
                  "required":true,
                  "content":{
                     "multipart/form-data":{
                        "schema":{
                           "$ref":"#/components/schemas/UploadFileDto"
                        }
                     }
                  }
               }
            }
         }
      }
      

      ...

      {
         "UploadFileDto":{
            "type":"object",
            "properties":{
               "file":{
                  "type":"file",
                  "properties":{
                     "file":{
                        "type":"string",
                        "format":"binary"
                     }
                  },
                  "description":"...",
                  "example":"'file': <any-kind-of-binary-file>"
               },
               "user_id":{
                  "type":"string",
                  "description":"...",
                  "example":"cus_IPqRS333voIGbS"
               }
            },
            "required":[
               "file",
               "user_id"
            ]
         }
      }
      

      【讨论】:

      • 你的答案不可读,我希望你提供了完整的例子,我在图片中看到的是我需要的,但我不明白你提供的代码应该放在哪里。
      猜你喜欢
      • 2020-06-12
      • 1970-01-01
      • 1970-01-01
      • 2020-02-24
      • 1970-01-01
      • 2015-12-29
      • 1970-01-01
      • 2016-07-22
      • 2021-09-18
      相关资源
      最近更新 更多