Skip to content

v4.0.0

Compare
Choose a tag to compare
@samchungy samchungy released this 10 Nov 05:51
· 15 commits to master since this release
1d960e9

What's Changed

Breaking Changes 🛠

  • .openapi() Breaking Change by @samchungy in #356

    .openapi() behaves a little differently now. It will now preserve previous openapi state except for ref and use it. This means that any metadata set on previous schema will now also be carried over to the next schema. Whilst I don't suspect this will impact too many users, it is still a breaking change nonetheless. Libraries which declare zod-openapi as a peer dependency, can safely set this version as a non breaking change for their library.

    const FooSchema = z
      .string()
      .transform((str => str.trim()))
      .openapi({ effectType: 'same', example: 'foo' });
    
    // in this version, this BarSchema now has `effectType: same` and `example: 'foo'` too
    const BarSchema = FooSchema.openapi({ description: "bar" });

    Why do we need this change?

    1. Unintuitive Extension

      const FooSchema = z.string().openapi({ ref: 'string' });
      
      const BarSchema = z.object({
        a: FooSchema,
        b: FooSchema.openapi({ description: 'foo' }),
      });
      
      createSchema(BarSchema)

      This previous generated the following:

      {
        schema: {
          type: 'object',
          properties: {
            a: { '$ref': '#/components/schemas/string' },
            b: { type: 'string', description: 'foo' }
          },
          required: [ 'a', 'b' ]
        },
        components: { string: { type: 'string' } }
      }

      However, it's clear that the user simply wanted to reuse the FooSchema but describe it as something else later on.

      After:

      {
        schema: {
          type: 'object',
          properties: {
            a: { '$ref': '#/components/schemas/string' },
            b: { '$ref': '#/components/schemas/string', description: 'foo' }
          },
          required: [ 'a', 'b' ]
        },
        components: { string: { type: 'string' } }
      }

      This also fixes an issue with the following example where .describe() is used in place of description.

      const FooSchema = z.string().openapi({ ref: 'string' });
      	
      const BarSchema = z.object({
        a: FooSchema,
        b: FooSchema.describe('foo')
      });
      	
      createSchema(BarSchema)

      This scenario previously caused us to throw an error because it attempts to register the FooSchema twice with different objects.

    2. Unregistered Base Schemas.

      Previously, if you were to use a schema like this, it would actually render an incorrect component. This change updates that behaviour to always generate the base schema as a component.

      Before:

      const FooSchema = z.string().uuid().openapi({ ref: 'id' });
      const BarSchema = FooSchema.describe('unique job id');
      
      createSchema(BarSchema);
      {
        schema: { '$ref': '#/components/schemas/id' },
        components: {
          id: { type: 'string', format: 'uuid', description: 'unique job id' }
        }
      }

      After:

      {
        schema: { '$ref': '#/components/schemas/id', description: 'unique job id' },
        components: { id: { type: 'string', format: 'uuid' } }
      }

      This change also updates some of the parsing logic for registered schemas with a description field.

      Before

       {
          'allOf': [
            '$ref': '#/components/schemas/foo',
            { "description": "bar"} ],
          ]
       }

      After in 3.1.0

      {
         '$ref': '#/components/schemas/foo',
         'description': 'bar',
      }

      After in 3.0.0

      {
         'allOf': [
           '$ref': '#/components/schemas/foo',
         ],
         'description': 'bar'
      }

      The nesting of additional fields alongside allOf has also been adjusted.

New Features 🎉

  • Add multipleOf support by @samchungy in #358

    z.number().multipleOf(3);

    Should now generate the following:

    {
      type: 'number',
      multipleOf: 3,
    }
  • Update Intersection Parser by @samchungy in #360

    This library will now attempt to flatten any intersection chains you may have which will reduce unnecessary nesting of allOf.

Full Changelog: v3.3.0...v4.0.0