zod-openapi 5.0.0-beta.20 → 5.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <h1 align="center">zod-openapi</h1>
4
4
  </p>
5
5
  <p align="center">
6
- A TypeScript library which uses <a href="https://github.com/colinhacks/zod">Zod</a> schemas to generate OpenAPI v3.1x documentation.
6
+ A TypeScript library which uses <a href="https://github.com/colinhacks/zod">Zod</a> schemas to generate OpenAPI v3.x documentation.
7
7
  </p>
8
8
  <div align="center">
9
9
  <a href="https://www.npmjs.com/package/zod-openapi"><img src="https://img.shields.io/npm/v/zod-openapi"/></a>
@@ -15,9 +15,6 @@ A TypeScript library which uses <a href="https://github.com/colinhacks/zod">Zod<
15
15
  </div>
16
16
  <br>
17
17
 
18
- > [!TIP]
19
- > Zod v4 support is available via `zod-openapi@beta`. Please read the [documentation](https://github.com/samchungy/zod-openapi/blob/v4-stash/docs/v5.md) for more information. A codegen will be available on release to help you migrate if you wish to wait.
20
-
21
18
  ## Installation
22
19
 
23
20
  Install via `npm`, `yarn`, or `pnpm`:
@@ -34,41 +31,33 @@ pnpm install zod zod-openapi
34
31
 
35
32
  ### `.meta()`
36
33
 
37
- Use the `.meta()` method to add OpenAPI metadata to a Zod schema. It accepts an object with the following options:
34
+ Use the `.meta()` method to add metadata to a Zod schema. It accepts an object with the following options:
38
35
 
39
36
  | Option | Description |
40
37
  | ---------- | ---------------------------------------------------------------------------------------------------------------- |
41
38
  | `id` | Registers a schema as a reusable OpenAPI component. |
42
39
  | `header` | Adds metadata for [response headers](#response-headers). |
43
40
  | `param` | Adds metadata for [request parameters](#parameters). |
44
- | `override` | Allows you to override the rendered OpenAPI schema. This takes either an object or a function. |
41
+ | `override` | Allows you to override the rendered OpenAPI schema. This takes either an object or a function |
45
42
  | `outputId` | Allows you to set a different ID for the output schema. This is useful when the input and output schemas differ. |
46
- | `unusedIO` | Allows you to set the `io` for an unused schema added to the components section. Defaults to `output`. |
47
-
48
- You can also set standard OpenAPI properties directly in the `.meta()` method, such as:
49
-
50
- ```typescript
51
- z.string().meta({
52
- description: 'A text field',
53
- example: 'Example value',
54
- });
55
- ```
43
+ | `unusedIO` | Allows you to set the `io` for an unused schema added to the components section. Defaults to `output` |
56
44
 
57
45
  ### `createDocument`
58
46
 
59
47
  Generates an OpenAPI documentation object.
60
48
 
61
49
  ```typescript
62
- import * as z from 'zod/v4';
50
+ import 'zod-openapi/extend';
51
+ import { z } from 'zod';
63
52
  import { createDocument } from 'zod-openapi';
64
53
 
65
- const jobId = z.string().meta({
54
+ const jobId = z.string().openapi({
66
55
  description: 'A unique identifier for a job',
67
56
  example: '12345',
68
57
  id: 'jobId',
69
58
  });
70
59
 
71
- const title = z.string().meta({
60
+ const title = z.string().openapi({
72
61
  description: 'Job title',
73
62
  example: 'My job',
74
63
  });
@@ -181,45 +170,37 @@ const document = createDocument({
181
170
  ```
182
171
  </details>
183
172
 
184
- `createDocument` takes an optional options argument which can be used to modify how the document is created
173
+ #### CreateDocumentOptions
174
+
175
+ `createDocument` takes an optional `CreateDocumentOptions` argument which can be used to modify how the document is created.
185
176
 
186
177
  ```typescript
187
- createDocument(doc, {
188
- override: ({ jsonSchema, zodSchema, io }) => {
189
- // Customize the schema generation
190
- if (io === 'output') {
191
- jsonSchema.type = 'string';
178
+ const document = createDocument(details, {
179
+ override: ({ jsonSchema, zodSchema }) => {
180
+ if (jsonSchema.anyOf) {
181
+ ctx.jsonSchema.oneOf = ctx.jsonSchema.anyOf;
182
+ delete ctx.jsonSchema.anyOf;
192
183
  }
193
184
  },
194
185
  });
195
186
  ```
196
187
 
197
- #### CreateDocumentOptions
198
-
199
- | Option | Type | Default | Description |
200
- | ------------------ | ------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------- |
201
- | `override` | `Function` | `undefined` | Override rendered schema with a function`` |
202
- | `outputIdSuffix` | `string` | `'Output'` | Suffix for output schema IDs when the schema is used in both a request and response |
203
- | `allowEmptySchema` | `boolean \| Object` | `false` | Control whether empty schemas are allowed. |
204
- | `cycles` | `'ref' \| 'throw'` | `'ref'` | How to handle cycles in schemas.<br>- `'ref'` — Break cycles using $defs<br>- `'throw'` — Error on cycles |
205
- | `reused` | `'ref' \| 'inline'` | `'inline'` | How to handle reused schemas.<br>- `'ref'` — Reused schemas as references<br>- `'inline'` — Inline reused schemas |
206
- | `schemaRefPath` | `string` | `'#/components/schemas/'` | Path prefix for schema references. Used when generating $ref values. |
207
-
208
188
  ### `createSchema`
209
189
 
210
190
  Creates an OpenAPI Schema Object along with any registered components. OpenAPI 3.1.0 Schema Objects are fully compatible with JSON Schema.
211
191
 
212
192
  ```typescript
213
- import * as z from 'zod/v4';
193
+ import 'zod-openapi/extend';
194
+ import { z } from 'zod';
214
195
  import { createSchema } from 'zod-openapi';
215
196
 
216
- const jobId = z.string().meta({
197
+ const jobId = z.string().openapi({
217
198
  description: 'A unique identifier for a job',
218
199
  example: '12345',
219
200
  id: 'jobId',
220
201
  });
221
202
 
222
- const title = z.string().meta({
203
+ const title = z.string().openapi({
223
204
  description: 'Job title',
224
205
  example: 'My job',
225
206
  });
@@ -264,17 +245,15 @@ const { schema, components } = createSchema(job);
264
245
 
265
246
  #### CreateSchemaOptions
266
247
 
267
- `createSchema` takes an optional `CreateSchemaOptions` parameter which includes all options from [CreateDocumentOptions](#createdocumentoptions) plus the following:
248
+ `createSchema` takes an optional `CreateSchemaOptions` parameter which can also take the same options as [CreateDocumentOptions](#createdocumentoptions) along with the following options:
268
249
 
269
250
  ```typescript
270
251
  const { schema, components } = createSchema(job, {
271
- // Input/Output context - controls how schemas are generated
272
- io: 'input', // 'input' for request bodies/params, 'output' for responses
273
-
274
- // Component handling
275
- schemaComponents: { jobId: z.string() }, // Pre-defined components to use
276
- schemaComponentRefPath: '#/definitions/', // Custom path prefix for component references
277
- });
252
+ schemaType: 'input'; // This controls whether this should be rendered as a request (`input`) or response (`output`). Defaults to `output`
253
+ openapi: '3.0.0'; // OpenAPI version to use, defaults to `'3.1.0'`
254
+ components: { jobId: z.string() } // Additional components to use and create while rendering the schema
255
+ componentRefPath: '#/definitions/' // Defaults to #/components/schemas/
256
+ })
278
257
  ```
279
258
 
280
259
  ### Request Parameters
@@ -306,7 +285,7 @@ createDocument({
306
285
  '/jobs/{a}': {
307
286
  put: {
308
287
  parameters: [
309
- z.string().meta({
288
+ z.string().openapi({
310
289
  param: {
311
290
  name: 'job-header',
312
291
  in: 'header',
@@ -417,7 +396,7 @@ If we take the example in `createDocument` and instead create `title` as follows
417
396
  ##### Auto Registering Schema
418
397
 
419
398
  ```typescript
420
- const title = z.string().meta({
399
+ const title = z.string().openapi({
421
400
  description: 'Job title',
422
401
  example: 'My job',
423
402
  id: 'jobTitle', // <- new field
@@ -455,14 +434,14 @@ Another way to register schema instead of adding a `ref` is to add it to the com
455
434
  eg.
456
435
 
457
436
  ```typescript
458
- const title = z.string().meta({
437
+ const title = z.string().openapi({
459
438
  description: 'Job title',
460
439
  example: 'My job',
461
440
  });
462
441
  createDocument({
463
442
  components: {
464
443
  schemas: {
465
- jobTitle: title, // this will register this Zod Schema as jobTitle unless `id` in `.meta()` is specified on the type
444
+ jobTitle: title, // this will register this Zod Schema as jobTitle unless `ref` in `.openapi()` is specified on the type
466
445
  },
467
446
  },
468
447
  });
@@ -474,7 +453,7 @@ Query, Path, Header & Cookie parameters can be similarly registered:
474
453
 
475
454
  ```typescript
476
455
  // Easy auto registration
477
- const jobId = z.string().meta({
456
+ const jobId = z.string().openapi({
478
457
  description: 'Job ID',
479
458
  example: '1234',
480
459
  param: { id: 'jobRef' },
@@ -495,7 +474,7 @@ createDocument({
495
474
  });
496
475
 
497
476
  // or more verbose auto registration
498
- const jobId = z.string().meta({
477
+ const jobId = z.string().openapi({
499
478
  description: 'Job ID',
500
479
  example: '1234',
501
480
  param: { in: 'header', name: 'jobId', id: 'jobRef' },
@@ -511,8 +490,8 @@ createDocument({
511
490
  },
512
491
  });
513
492
 
514
- // or manual registration
515
- const otherJobId = z.string().meta({
493
+ // or manual registeration
494
+ const otherJobId = z.string().openapi({
516
495
  description: 'Job ID',
517
496
  example: '1234',
518
497
  param: { in: 'header', name: 'jobId' },
@@ -532,7 +511,7 @@ createDocument({
532
511
  Response headers can be similarly registered:
533
512
 
534
513
  ```typescript
535
- const header = z.string().meta({
514
+ const header = z.string().openapi({
536
515
  description: 'Job ID',
537
516
  example: '1234',
538
517
  header: { id: 'some-header' },
@@ -540,7 +519,7 @@ const header = z.string().meta({
540
519
 
541
520
  // or
542
521
 
543
- const jobIdHeader = z.string().meta({
522
+ const jobIdHeader = z.string().openapi({
544
523
  description: 'Job ID',
545
524
  example: '1234',
546
525
  });
@@ -636,121 +615,6 @@ createDocument({
636
615
  });
637
616
  ```
638
617
 
639
- #### Path Items
640
-
641
- Path Items can also be registered
642
-
643
- ```typescript
644
- const pathItem: ZodOpenApiPathItemObject = {
645
- id: 'some-path-item',
646
- get: {
647
- responses: {
648
- 200: {
649
- description: '200 OK',
650
- content: {
651
- 'application/json': {
652
- schema: z.object({ a: z.string() }),
653
- },
654
- },
655
- },
656
- },
657
- },
658
- };
659
-
660
- // or
661
-
662
- createDocument({
663
- components: {
664
- pathItems: {
665
- 'some-path-item': pathItem,
666
- },
667
- },
668
- });
669
- ```
670
-
671
- #### Security Schemes
672
-
673
- Security Schemes can be registered for authentication methods:
674
-
675
- ```typescript
676
- createDocument({
677
- components: {
678
- securitySchemes: {
679
- bearerAuth: {
680
- type: 'http',
681
- scheme: 'bearer',
682
- bearerFormat: 'JWT',
683
- description: 'JWT Authentication',
684
- },
685
- },
686
- },
687
- });
688
- ```
689
-
690
- #### Links
691
-
692
- Links can be registered to describe relationships between operations:
693
-
694
- ```typescript
695
- const link: ZodOpenApiLinkObject = {
696
- id: 'getUserById',
697
- operationId: 'getUser',
698
- parameters: {
699
- userId: '$request.path.id',
700
- },
701
- description: 'Link to get user by id',
702
- };
703
-
704
- // or
705
-
706
- createDocument({
707
- components: {
708
- links: {
709
- getUserById: {
710
- operationId: 'getUser',
711
- parameters: {
712
- userId: '$request.path.id',
713
- },
714
- description: 'Link to get user by id',
715
- },
716
- },
717
- },
718
- });
719
- ```
720
-
721
- #### Examples
722
-
723
- Examples can be registered to provide sample values for schemas:
724
-
725
- ```typescript
726
- const example: ZodOpenApiExampleObject = {
727
- id: 'userExample',
728
- summary: 'A sample user',
729
- value: {
730
- id: '123',
731
- name: 'Jane Doe',
732
- email: 'jane@example.com',
733
- },
734
- };
735
-
736
- // or
737
-
738
- createDocument({
739
- components: {
740
- examples: {
741
- userExample: {
742
- summary: 'A sample user',
743
- value: {
744
- id: '123',
745
- name: 'Jane Doe',
746
- email: 'jane@example.com',
747
- },
748
- },
749
- },
750
- },
751
- });
752
- ```
753
-
754
618
  ### Zod Types
755
619
 
756
620
  Zod types are composed of two different parts: the input and the output. This library decides which type to create based on if it is used in a request or response context.
@@ -767,13 +631,13 @@ Output:
767
631
 
768
632
  In general, you want to avoid using a registered input schema in an output context and vice versa. This is because the rendered input and output schemas of a simple Zod schema will differ, even with a simple Zod schema like `z.object()`.
769
633
 
770
- ```typescript
634
+ ```ts
771
635
  const schema = z.object({
772
636
  name: z.string(),
773
637
  });
774
638
  ```
775
639
 
776
- Input schemas (request bodies, parameters):
640
+ Input:
777
641
 
778
642
  ```json
779
643
  {
@@ -787,7 +651,7 @@ Input schemas (request bodies, parameters):
787
651
  }
788
652
  ```
789
653
 
790
- Output schemas (responses):
654
+ Output:
791
655
 
792
656
  ```json
793
657
  {
@@ -802,30 +666,25 @@ Output schemas (responses):
802
666
  }
803
667
  ```
804
668
 
805
- When the same schema is referenced in both input and output contexts, the library generates two separate component schemas. This happens automatically when a schema with an ID is used in both contexts.
669
+ Unless you are strictly using `z.looseObject()`s or `z.strictObject()`s throughout your codebase you will likely run into issues where the input and output schemas differ. This library will do a best effort to check equality using a simple JSON.stringify() === JSON.stringify() check. If your registered schema contains dynamically created components, this will always fail.
806
670
 
807
- You can customize the output schema name by providing an `outputId`:
671
+ If the schemas are not equal, it will automatically handle this by outputting the `output` schema with an `Output` suffix.
672
+
673
+ You can override this by setting the `outputId` field with the `.meta()` method.
808
674
 
809
675
  ```ts
810
676
  const schema = z
811
677
  .object({
812
678
  name: z.string(),
813
679
  })
814
- .meta({
815
- id: 'MyObject',
816
- outputId: 'MyObjectResponse', // Customize the output schema name
817
- });
680
+ .meta({ id: 'MyObject', outputId: 'MyObjectResponse' });
818
681
  ```
819
682
 
820
- You can also set a global suffix for output schemas or use `z.looseObject()` and `z.strictObject()` to have explicit control over the schema behavior.
821
-
822
- > **⚠️ Note:** If your registered schema contains dynamically created lazy components, they won't be reused between input and output schemas.
823
-
824
683
  ## Supported OpenAPI Versions
825
684
 
826
685
  Currently the following versions of OpenAPI are supported
827
686
 
828
- - `3.1.0` (minimum version)
687
+ - `3.1.0`
829
688
  - `3.1.1`
830
689
 
831
690
  Setting the `openapi` field will change how the some of the components are rendered.
@@ -867,10 +726,6 @@ See the library in use in the [examples](./examples/) folder.
867
726
 
868
727
  - [eslint-plugin-zod-openapi](https://github.com/samchungy/eslint-plugin-zod-openapi) - Eslint rules for zod-openapi. This includes features which can autogenerate Typescript comments for your Zod types based on your `description`, `example` and `deprecated` fields.
869
728
 
870
- ## Version Information
871
-
872
- For information about changes and migration from v4 to v5, see the [v5 migration guide](./docs/v5.md).
873
-
874
729
  ## Comparisons
875
730
 
876
731
  ### [@asteasolutions/zod-to-openapi](./docs/comparisons.md)
package/dist/api.d.mts CHANGED
@@ -1,11 +1,22 @@
1
- import { ComponentRegistry, Override, createComponents, createRegistry } from "./components-DkESnIB9.mjs";
1
+ import { ComponentRegistry, MediaTypeObject, Override, ParameterLocation, ParameterObject, ReferenceObject, ZodOpenApiMediaTypeObject, createComponents, createRegistry, isAnyZodType } from "./components-DAYTA1Um.mjs";
2
2
  import { $ZodObject, $ZodType, $ZodTypes } from "zod/v4/core";
3
- import { core } from "zod/v4";
4
3
 
4
+ //#region src/create/content.d.ts
5
+ declare const createMediaTypeObject: (mediaTypeObject: ZodOpenApiMediaTypeObject, ctx: {
6
+ registry: ComponentRegistry;
7
+ io: "input" | "output";
8
+ }, path: string[]) => MediaTypeObject;
9
+ //#endregion
10
+ //#region src/create/parameters.d.ts
11
+ declare const createParameter: (parameter: $ZodType, location: {
12
+ in: ParameterLocation;
13
+ name: string;
14
+ } | undefined, ctx: {
15
+ registry: ComponentRegistry;
16
+ io: "input" | "output";
17
+ }, path: string[]) => ParameterObject | ReferenceObject;
18
+ //#endregion
5
19
  //#region src/create/object.d.ts
6
20
  declare const unwrapZodObject: (zodType: $ZodTypes, io: "input" | "output", path: string[]) => $ZodObject;
7
21
  //#endregion
8
- //#region src/zod.d.ts
9
- declare const isAnyZodType: (schema: unknown) => schema is core.$ZodTypes;
10
- //#endregion
11
- export { ComponentRegistry, Override, createComponents, createRegistry, isAnyZodType, unwrapZodObject };
22
+ export { Override, createComponents, createMediaTypeObject, createParameter, createRegistry, isAnyZodType, unwrapZodObject };
package/dist/api.d.ts CHANGED
@@ -1,11 +1,22 @@
1
- import { ComponentRegistry, Override, createComponents, createRegistry } from "./components-BLmIpmmY.js";
1
+ import { ComponentRegistry, MediaTypeObject, Override, ParameterLocation, ParameterObject, ReferenceObject, ZodOpenApiMediaTypeObject, createComponents, createRegistry, isAnyZodType } from "./components-5_CJdR73.js";
2
2
  import { $ZodObject, $ZodType, $ZodTypes } from "zod/v4/core";
3
- import { core } from "zod/v4";
4
3
 
4
+ //#region src/create/content.d.ts
5
+ declare const createMediaTypeObject: (mediaTypeObject: ZodOpenApiMediaTypeObject, ctx: {
6
+ registry: ComponentRegistry;
7
+ io: "input" | "output";
8
+ }, path: string[]) => MediaTypeObject;
9
+ //#endregion
10
+ //#region src/create/parameters.d.ts
11
+ declare const createParameter: (parameter: $ZodType, location: {
12
+ in: ParameterLocation;
13
+ name: string;
14
+ } | undefined, ctx: {
15
+ registry: ComponentRegistry;
16
+ io: "input" | "output";
17
+ }, path: string[]) => ParameterObject | ReferenceObject;
18
+ //#endregion
5
19
  //#region src/create/object.d.ts
6
20
  declare const unwrapZodObject: (zodType: $ZodTypes, io: "input" | "output", path: string[]) => $ZodObject;
7
21
  //#endregion
8
- //#region src/zod.d.ts
9
- declare const isAnyZodType: (schema: unknown) => schema is core.$ZodTypes;
10
- //#endregion
11
- export { ComponentRegistry, Override, createComponents, createRegistry, isAnyZodType, unwrapZodObject };
22
+ export { Override, createComponents, createMediaTypeObject, createParameter, createRegistry, isAnyZodType, unwrapZodObject };
package/dist/api.js CHANGED
@@ -1,6 +1,8 @@
1
- const require_components = require('./components-XnOyQ3JZ.js');
1
+ require('./zod-i2t01GF0.js');
2
+ const require_components = require('./components-CXjVnBr-.js');
2
3
 
3
4
  exports.createComponents = require_components.createComponents;
5
+ exports.createMediaTypeObject = require_components.createMediaTypeObject;
6
+ exports.createParameter = require_components.createParameter;
4
7
  exports.createRegistry = require_components.createRegistry;
5
- exports.isAnyZodType = require_components.isAnyZodType;
6
8
  exports.unwrapZodObject = require_components.unwrapZodObject;
package/dist/api.mjs CHANGED
@@ -1,3 +1,4 @@
1
- import { createComponents, createRegistry, isAnyZodType, unwrapZodObject } from "./components-BVy-T4wz.mjs";
1
+ import "./zod-BvA30wad.mjs";
2
+ import { createComponents, createMediaTypeObject, createParameter, createRegistry, unwrapZodObject } from "./components-CvutxtFV.mjs";
2
3
 
3
- export { createComponents, createRegistry, isAnyZodType, unwrapZodObject };
4
+ export { createComponents, createMediaTypeObject, createParameter, createRegistry, unwrapZodObject };