网站搜索

typescript - NestJS Swagger 使用 Zod 的多部分文件上传问题


我正在开发一个 NestJS 应用程序,并使用 nestjs-zod 库进行验证和 swagger 文档。然而,当我尝试在 multipart form-data 请求中上传文件时,遇到了问题。

问题是我用来验证的 zod 没有特定的 File 类型,并且 Swagger 不会将其识别为文件输入,因为它缺少 @ApiProperty({ format: 'binary' }) 装饰。我正在寻找一种解决方案,以便使用 zod 正确地记录和验证多部分文件上传,同时我希望继续使用我正在做的 Dtos。

dto.ts
import { createZodDto } from 'nestjs-zod/dto';
import * as z from 'nestjs-zod/z';

export const schema = z.object({
  field: z.string().optional(),
  requiredFile: z
    .string()
    .refine((str: any): str is Buffer => Buffer.isBuffer(Buffer.from(str))),
  optionalFile: z
    .string()
    .refine((str: any): str is Buffer => Buffer.isBuffer(Buffer.from(str)))
    .optional(),
});

export class Dto extends createZodDto(schema) {}
controller.ts
@Post()
@UseInterceptors(
  FileFieldsInterceptor(
    [{ name: 'requiredFile' }, { name: 'optionalFile' }],
    multerLimits,
  ),
)
@ApiConsumes('multipart/form-data')
async create(
  @Body() dto: CreateStoreDto,
  @UploadedFiles()
  files,
) {
  // Handle the request...
}

我也尝试过使用 zod-to-openapi 包,但什么都没有改变!

dto2.ts
import { createZodDto } from 'nestjs-zod/dto';
import { z as z2 } from 'nestjs-zod/z';
import { extendZodWithOpenApi } from '@asteasolutions/zod-to-openapi';

extendZodWithOpenApi(z2);

export const schema = z2.object({
  optionalFile: z2
    .custom<Express.Multer.File>()
    .openapi({ format: 'binary', type: 'string' }),
  requiredFile: z2
    .string()
    .refine((str: any): str is Buffer => Buffer.isBuffer(Buffer.from(str)))
    .openapi({ type: 'string', format: 'binary' }),
});

export class Dto extends createZodDto(schema) {}

我也尝试了

  file3: z2.string().openapi({ type: 'string', format: 'binary' }),

但是那也不起作用

这是你可以 fork 并尝试提交 PR 修复问题的 GitHub 仓库: https://github.com/mohrazzak/nodejs

答案#1

我刚偶然发现这个,你的帖子帮我找到了答案。

    image: z.custom<Express.Multer.File>().openapi({
      type: 'string',
      description: 'The image to classify',
      format: 'binary'
    })

这似乎在 ValidationPipe 下工作得很好,但仍然保持 openapi 规范正确。

答案#2

我用这个来解决这个问题

import { createZodDto } from '@anatine/zod-nestjs';
import { extendZodWithOpenApi, extendApi } from '@anatine/zod-openapi';
import { ProductSchema } from 'src/generated';
import { SupportedLanguages } from 'src/shared/enums/supported-languages.enum';
import * as z from 'zod';

extendZodWithOpenApi(z);

const baseSchema = ProductSchema.pick({
    name: z.string(),
    description: z.string()
);

const CreateProductDtoSchema = extendApi(baseSchema, {
  properties: {
    productImages: {
      type: 'array',
      minItems: 1,
      items: { type: 'string', format: 'binary' },
    },
  },
  required: ['productImages'],
});

export class CreateProductDto extends createZodDto(CreateProductDtoSchema) {}

相关文章