zod-to-openapi icon indicating copy to clipboard operation
zod-to-openapi copied to clipboard

zod v4 support

Open wenerme opened this issue 8 months ago β€’ 1 comments

running with zod v4 will failed with

@asteasolutions/zod-to-openapi/dist/index.cjs:48
        const result = zodModifier.apply(this, args);
                                   ^

TypeError: Cannot read properties of undefined (reading 'apply')

v4 now support meta & jsonschema, this may make zod-to-openapi easier

wenerme avatar Apr 15 '25 09:04 wenerme

linking my Zod 4 PR so people can find this tracking issue: https://github.com/colinhacks/zod/pull/4074

colinhacks avatar Apr 18 '25 03:04 colinhacks

@colinhacks first of all cudos on everything you've done in V4. On the topic, sadly we've been very busy lately and never got the chance to start working on this. I did manage to startup the project using v4 today but it would require a lot of development to make things actually work as they did before. I know in your posts you've mentioned a 6-8 weeks until go-live. Do you have a date in mind? Just trying to figure out what our next steps might be

AGalabov avatar May 16 '25 13:05 AGalabov

Hi @AGalabov !.

We are also working on some things to support Zod v4. We can refer to the "For library authors" section of the Zod documents:

https://v4.zod.dev/library-authors

The v4 will be released today or tomorrow, right? @colinhacks

I know you are busy, but if the zod-to-openapi supports v4, we can work on about Zod OpenAPI. BUT, you don't hurry!

yusukebe avatar May 19 '25 03:05 yusukebe

I am right now implementing zod 3 and zod-to-openapi in our companies codebase and looking to upgrade to Zod 4 once an openapi conversion solution is ready.

If you guys need any help from a slightly above-average typescript coder, let me know :)

hoopyfroody avatar May 19 '25 14:05 hoopyfroody

@yusukebe zod supports toJSONSchema natively now, which means for openapi 3.1 which it’s compatible with JSON schema, no external dependencies needed and just zod itself is enough.

valerii15298 avatar May 20 '25 09:05 valerii15298

@valerii15298 you are correct on that. There are lots of cases that would be covered by zod itself when it comes to basic schemas. However things like:

  1. Schemas in parameters
  2. Automatically linking extended schemas
  3. Anything to do with actual endpoints - i.e path, params, query, body registration cannot be dune with pure zod (and correctly so).

As for everyone here. I am trying to squeeze in extra time to work on this. This is the PR that I'd be working on. As of right now I've got to 162 out of 213 working tests. It is a relatively quick process but there are some things to figure out based on the new structure of zod's internals.

I'll keep you posted

AGalabov avatar May 20 '25 10:05 AGalabov

Beta version is here!

All tests pass

Image

There is still stuff to be done but I've released a beta version: 7.3.1-beta-zod-v4-2 available in npm. We can use that for testing

AGalabov avatar May 23 '25 13:05 AGalabov

anyone has been able to to test the lazy issue ? :)

dr1ss avatar May 24 '25 11:05 dr1ss

Just tryed to convert one of my projects, everything seem to work so far.. the lazy problem is still here tho :( :

This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason: UnknownZodTypeError { message: 'Unknown zod object type, please specify typeand other OpenAPI props usingZodSchema.openapi.', data: { currentSchema: { type: 'lazy', getter: [Function (anonymous)] }, schemaName: undefined } }

dr1ss avatar May 24 '25 13:05 dr1ss

@dr1ss I am glad to hear that! And yes we've not worked on the support for z.lazy at all

AGalabov avatar May 27 '25 08:05 AGalabov

I converted our codebase to zod v4 (3.25.30) and zod-to-openapi v7.3.1-beta-zod-v4-2.

There seems to be an issue with discriminated unions and .extend(). This is a minimal reproduction:

This zod code:

const BaseTestSchema = z.object({
  type: z.literal('CALCULATION_RESULT'),
  calculation_type: z.enum(['LUMPSUM', 'MULTIPLY_BY']),
});

const CalculationResultSchema = z
  .discriminatedUnion('calculation_type', [
    BaseTestSchema.extend({
      calculation_type: z.literal('LUMPSUM'),
    }).openapi('CalculationResultLumpsummy'),
    BaseTestSchema.extend({
      calculation_type: z.literal('MULTIPLY_BY'),
    }).openapi('CalculationResultMultiplyy'),
  ])
  .openapi('CalculationResultSchema');

Results in this openApi result, where the discriminator is not correctly set:

CalculationResultLumpsummy:
      type: object
      properties:
        type:
          type: string
          enum:
            - CALCULATION_RESULT
        calculation_type:
          type: string
          enum:
            - LUMPSUM
      required:
        - type
        - calculation_type
    CalculationResultMultiplyy:
      type: object
      properties:
        type:
          type: string
          enum:
            - CALCULATION_RESULT
        calculation_type:
          type: string
          enum:
            - MULTIPLY_BY
      required:
        - type
        - calculation_type
    CalculationResultSchema:
      oneOf:
        - $ref: "#/components/schemas/CalculationResultLumpsummy"
        - $ref: "#/components/schemas/CalculationResultMultiplyy"
      discriminator:
        propertyName: type # incorrect, should be calculation_type
        mapping:
          CALCULATION_RESULT: "#/components/schemas/CalculationResultMultiplyy"

Looks like it somehow is not correctly using the discriminator and falling back to... the first property maybe?

hoopyfroody avatar May 27 '25 13:05 hoopyfroody

@hoopyfroody yes this has been addressed in the latest commits.

AGalabov avatar Jun 06 '25 14:06 AGalabov

And now an "official" and stable beta version is here!

After active discussions on #301 I believe we've reached a good enough point where the code does match the quality that we want. There is now an official beta version: 8.0.0-beta.2 available in npm.

Anyone can use the latest beta version using:

npm install @asteasolutions/zod-to-openapi@beta

The plan is to use this for a while. Merge the PR. See if any outstanding issues popup and track them as separate issues (and PRs) and eventually release this as an official "latest" version.

AGalabov avatar Jun 06 '25 14:06 AGalabov

Excited for this release !!! :D :D

bombillazo avatar Jun 13 '25 13:06 bombillazo

I updated to beta 4, and it still looks good to me. πŸ‘ πŸš€

kernwig avatar Jun 16 '25 21:06 kernwig

Hello, thanks for this new version.

I'm in the process of upgrading to v4, but looks like you are using zod/v4 so I'm wondering if zod/v4-mini would be supported ?

In my use case, I want to have tree-shaking as my zod definitions are also used in client side. Hence, I maintain a separate registry which can be remove client-side via tree-shaking.

I am mainly using the OpenApiRegistry, and I'm looking for a way to use the zod registry as param to retrieve metadata from.

Do you have any suggestions ?

moroine avatar Jun 17 '25 12:06 moroine

For cross reference, here is a draft PR trying to implement support of zod-mini https://github.com/asteasolutions/zod-to-openapi/pull/315

moroine avatar Jun 19 '25 11:06 moroine

fyi: Zod v4 is now out and the suffixes are gone.

jbergstroem avatar Jul 15 '25 14:07 jbergstroem

This has now been released as an official v8.0.0 Release πŸš€

AGalabov avatar Jul 15 '25 20:07 AGalabov