我的 NestJS 服务器有一个接受文件和其他表单数据的端点。例如,我在表单中传递了一个文件和文件创建者的 user_id。
NestJS Swagger 需要明确告知 body 包含该文件,并且端点使用multipart/form-data
该文件在 NestJS 文档https://docs.nestjs.com/openapi/types-and-parameters#types-and-parameters中没有记录。
我的 NestJS 服务器有一个接受文件和其他表单数据的端点。例如,我在表单中传递了一个文件和文件创建者的 user_id。
NestJS Swagger 需要明确告知 body 包含该文件,并且端点使用multipart/form-data
该文件在 NestJS 文档https://docs.nestjs.com/openapi/types-and-parameters#types-and-parameters中没有记录。
幸运的是,一些错误引发了关于如何处理这个用例的讨论
查看这两个讨论 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"
]
}
}
这是我发现的更清洁的方法:
@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