Skip to content

generateOpenApiSpec does not handle File fields in FormData #26

@GorgeousPuree

Description

@GorgeousPuree
export const NewOrderImageDTO = z.object({
  orderId: z.string().transform((value) => {
    const parsed = parseInt(value, 10);
    if (isNaN(parsed) || parsed <= 0) {
      throw new Error('orderId must be a positive number');
    }
    return parsed;
  }),
  orderFileType: z.nativeEnum(MediaFileType),
  orderFile: ImageFileDTO,
});

export const MAX_FILE_SIZE = 4500000;

export const ACCEPTED_IMAGE_TYPES = [
  'image/jpeg',
  'image/jpg',
  'image/png',
  'image/webp',
];

export const ImageFileDTO = z
  .custom<File>((v) => v instanceof File)
  .refine((file) => {
    if (file && (file.size === 0 || file.name === undefined)) return false;
    else return true;
  }, 'Please update or add new image.')
  .refine(
    (file) => ACCEPTED_IMAGE_TYPES.includes(file?.type),
    '.jpg, .jpeg, .png and .webp files are accepted.'
  )
  .refine(
    (file) => file.size <= MAX_FILE_SIZE,
    `Max file size is ${MAX_FILE_SIZE / 1000 / 1000}MB.`
  );
export const { POST } = defineRoute({
  operationId: 'addOrderImage',
  method: 'POST',
  summary: 'Add an order image',
  description: 'Add/replace specified image in the order',
  tags: ['Order images'],
  hasFormData: true,
  requestBody: NewOrderImageDTO,
  action: async ({ body }) => {
    await addOrderImage(body);
    return Response.json({ status: 201 });
  },
  responses: {
    201: { description: 'Order image created successfully' },
    400: { description: 'Bad order params' },
    403: { description: 'No access to selected club location' },
  },
});

As you can see I'm defining my File field using zod as .custom<File>((v) => v instanceof File).
When you open Swagger page you see that instead of file browser field, my field accepts string.
If I open /api/swagger (route that returns generateOpenApiSpec json), I can see that orderFile is of type object: "orderFile":{}.
Zod doesn't have special type for files, using .custom<File> or .instanceof(File) are common approaches, so I think generateOpenApiSpec should handle files fields differently by checking if object is an instance of file...
image

Desired behavior is to have file browser fields in the swagger, i.e. file fields returned by generateOpenApiSpec should be like "orderFile":{ "type": "file"}
image

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions