anatine / zod-plugins

Plugins and utilities for Zod
637 stars 89 forks source link

[zod-openapi][zod-nestjs] Object with only one optional property gets marked as required. #190

Open DoubleJ-G opened 6 months ago

DoubleJ-G commented 6 months ago

I am using this in a NestJS Query DTO

async find(@Query() { siteId }: GetVehiclesDto) {}
export const GetVehiclesZ = extendApi(
  z.object({
    siteId: z.string().optional(),
  }),
  {
    title: 'Example',
  },
);

export class GetVehiclesDto extends createZodDto(GetVehiclesZ) {}

Incorrectly outputs a schema with it marked as required.

"parameters": [{
  "name": "siteId",
  "required": true,
  "in": "query",
  "schema": {
    "type": "string"
  }
}],

If I add another property to z.object({}) though it is correctly marked as required: false

DoubleJ-G commented 6 months ago

Note: any number of optional fields are marked as required UNTIL at least one other actually required field is in the schema

AlexanderMac commented 3 months ago

A simple fix is to call extendApi function with the schema and the schema object parameters (required field has to be empty):

import { extendApi } from '@anatine/zod-openapi';

export const QuerySchema = extendApi(z.object({
  offset: z.number().optional(),
  count: z.number().optional(),
}), {
  required: [],
});
Papooch commented 1 month ago

Also running into this. As long as all fields in the schema are optional, @anatine/zod-openapi interprets everyting as required.

It seems to only be happening in case of query parameters.

Currently using @AlexanderMac's workaround. The only issue is that you have to remember to remove it once you add any actually required property.

The simplest fix is to change this line https://github.com/anatine/zod-plugins/blob/main/packages/zod-openapi/src/lib/zod-openapi.ts#L251

-const required = requiredProperties.length > 0 ? { required: requiredProperties } : {};
+const required = requiredProperties.length > 0 ? { required: requiredProperties } : { required: [] };

But I'm not sure if that's a proper fix, because we'd be explicitly adding an empty required array to the schema.

In reality, the issue is probably somewhere in the @anatine/zod-nestjs package, or even @nestjs/swagger, which improperly parses the required field, but I wasn't able to find where.