#file-upload #swagger #nestjs #openapi #nestjs-swagger
#загрузка файла #развязность #nestjs #openapi #nestjs-развязность
Вопрос:
На моем сервере NestJS есть конечная точка, которая принимает файлы, а также дополнительные данные формы, например, я передаю файл и идентификатор пользователя создателя файла в форме.
NestJS Swagger необходимо явно указать, что body содержит файл и что конечная точка использует multipart/form-data
это не задокументировано в документах NestJS https://docs.nestjs.com/openapi/types-and-parameters#types-and-parameters .
Ответ №1:
К счастью, некоторые ошибки привели к обсуждению того, как справиться с этим вариантом использования
глядя на эти два обсуждения 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"
]
}
}
Комментарии:
1. Ваш ответ не читается, я бы хотел, чтобы вы предоставили полный пример, то, что я вижу на изображениях, — это то, что мне нужно, но я не мог понять, куда поместить предоставленный вами код.
Ответ №2:
Вот что я нахожу более чистым подходом:
@Injectable()
class FileToBodyInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const ctx = context.switchToHttp();
const req = ctx.getRequest();
if(req.body amp;amp; 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