3

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

在此处输入图像描述

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

4

2 回答 2

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-11-30T23:48:39.853 回答
0

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

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

FileToBodyInterceptor并且ApiFile很一般,我希望他们在 NestJs 中的位置

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

于 2021-01-14T10:16:53.433 回答