zod-openapi 5.0.0-beta.18 → 5.0.0-beta.2

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,12 +3,12 @@
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>
10
10
  <a href="https://www.npmjs.com/package/zod-openapi"><img src="https://img.shields.io/npm/dm/zod-openapi"/></a>
11
- <a href="https://nodejs.org/en/"><img src="https://img.shields.io/node/v/zod-openapi"/></a>
11
+ <a href="https://nodejs.org/en/"><img src="https://img.shields.io/badge/node-%3E%3D%2018-brightgreen"/></a>
12
12
  <a href="https://github.com/samchungy/zod-openapi/actions/workflows/test.yml"><img src="https://github.com/samchungy/zod-openapi/actions/workflows/test.yml/badge.svg"/></a>
13
13
  <a href="https://github.com/samchungy/zod-openapi/actions/workflows/release.yml"><img src="https://github.com/samchungy/zod-openapi/actions/workflows/release.yml/badge.svg"/></a>
14
14
  <a href="https://github.com/seek-oss/skuba"><img src="https://img.shields.io/badge/🤿%20skuba-powered-009DC4"/></a>
@@ -31,41 +31,33 @@ pnpm install zod zod-openapi
31
31
 
32
32
  ### `.meta()`
33
33
 
34
- 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:
35
35
 
36
36
  | Option | Description |
37
37
  | ---------- | ---------------------------------------------------------------------------------------------------------------- |
38
38
  | `id` | Registers a schema as a reusable OpenAPI component. |
39
39
  | `header` | Adds metadata for [response headers](#response-headers). |
40
40
  | `param` | Adds metadata for [request parameters](#parameters). |
41
- | `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 |
42
42
  | `outputId` | Allows you to set a different ID for the output schema. This is useful when the input and output schemas differ. |
43
- | `unusedIO` | Allows you to set the `io` for an unused schema added to the components section. Defaults to `output`. |
44
-
45
- You can also set standard OpenAPI properties directly in the `.meta()` method, such as:
46
-
47
- ```typescript
48
- z.string().meta({
49
- description: 'A text field',
50
- example: 'Example value',
51
- });
52
- ```
43
+ | `unusedIO` | Allows you to set the `io` for an unused schema added to the components section. Defaults to `output` |
53
44
 
54
45
  ### `createDocument`
55
46
 
56
47
  Generates an OpenAPI documentation object.
57
48
 
58
49
  ```typescript
50
+ import 'zod-openapi/extend';
59
51
  import { z } from 'zod';
60
52
  import { createDocument } from 'zod-openapi';
61
53
 
62
- const jobId = z.string().meta({
54
+ const jobId = z.string().openapi({
63
55
  description: 'A unique identifier for a job',
64
56
  example: '12345',
65
57
  id: 'jobId',
66
58
  });
67
59
 
68
- const title = z.string().meta({
60
+ const title = z.string().openapi({
69
61
  description: 'Job title',
70
62
  example: 'My job',
71
63
  });
@@ -178,45 +170,37 @@ const document = createDocument({
178
170
  ```
179
171
  </details>
180
172
 
181
- `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.
182
176
 
183
177
  ```typescript
184
- createDocument(doc, {
185
- override: ({ jsonSchema, zodSchema, io }) => {
186
- // Customize the schema generation
187
- if (io === 'output') {
188
- 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;
189
183
  }
190
184
  },
191
185
  });
192
186
  ```
193
187
 
194
- #### CreateDocumentOptions
195
-
196
- | Option | Type | Default | Description |
197
- | ------------------ | ------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------- |
198
- | `override` | `Function` | `undefined` | Override rendered schema with a function`` |
199
- | `outputIdSuffix` | `string` | `'Output'` | Suffix for output schema IDs when the schema is used in both a request and response |
200
- | `allowEmptySchema` | `boolean \| Object` | `false` | Control whether empty schemas are allowed. |
201
- | `cycles` | `'ref' \| 'throw'` | `'ref'` | How to handle cycles in schemas.<br>- `'ref'` — Break cycles using $defs<br>- `'throw'` — Error on cycles |
202
- | `reused` | `'ref' \| 'inline'` | `'inline'` | How to handle reused schemas.<br>- `'ref'` — Reused schemas as references<br>- `'inline'` — Inline reused schemas |
203
- | `schemaRefPath` | `string` | `'#/components/schemas/'` | Path prefix for schema references. Used when generating $ref values. |
204
-
205
188
  ### `createSchema`
206
189
 
207
190
  Creates an OpenAPI Schema Object along with any registered components. OpenAPI 3.1.0 Schema Objects are fully compatible with JSON Schema.
208
191
 
209
192
  ```typescript
193
+ import 'zod-openapi/extend';
210
194
  import { z } from 'zod';
211
195
  import { createSchema } from 'zod-openapi';
212
196
 
213
- const jobId = z.string().meta({
197
+ const jobId = z.string().openapi({
214
198
  description: 'A unique identifier for a job',
215
199
  example: '12345',
216
200
  id: 'jobId',
217
201
  });
218
202
 
219
- const title = z.string().meta({
203
+ const title = z.string().openapi({
220
204
  description: 'Job title',
221
205
  example: 'My job',
222
206
  });
@@ -261,17 +245,15 @@ const { schema, components } = createSchema(job);
261
245
 
262
246
  #### CreateSchemaOptions
263
247
 
264
- `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:
265
249
 
266
250
  ```typescript
267
251
  const { schema, components } = createSchema(job, {
268
- // Input/Output context - controls how schemas are generated
269
- io: 'input', // 'input' for request bodies/params, 'output' for responses
270
-
271
- // Component handling
272
- schemaComponents: { jobId: z.string() }, // Pre-defined components to use
273
- schemaComponentRefPath: '#/definitions/', // Custom path prefix for component references
274
- });
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
+ })
275
257
  ```
276
258
 
277
259
  ### Request Parameters
@@ -303,7 +285,7 @@ createDocument({
303
285
  '/jobs/{a}': {
304
286
  put: {
305
287
  parameters: [
306
- z.string().meta({
288
+ z.string().openapi({
307
289
  param: {
308
290
  name: 'job-header',
309
291
  in: 'header',
@@ -414,7 +396,7 @@ If we take the example in `createDocument` and instead create `title` as follows
414
396
  ##### Auto Registering Schema
415
397
 
416
398
  ```typescript
417
- const title = z.string().meta({
399
+ const title = z.string().openapi({
418
400
  description: 'Job title',
419
401
  example: 'My job',
420
402
  id: 'jobTitle', // <- new field
@@ -452,14 +434,14 @@ Another way to register schema instead of adding a `ref` is to add it to the com
452
434
  eg.
453
435
 
454
436
  ```typescript
455
- const title = z.string().meta({
437
+ const title = z.string().openapi({
456
438
  description: 'Job title',
457
439
  example: 'My job',
458
440
  });
459
441
  createDocument({
460
442
  components: {
461
443
  schemas: {
462
- 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
463
445
  },
464
446
  },
465
447
  });
@@ -471,7 +453,7 @@ Query, Path, Header & Cookie parameters can be similarly registered:
471
453
 
472
454
  ```typescript
473
455
  // Easy auto registration
474
- const jobId = z.string().meta({
456
+ const jobId = z.string().openapi({
475
457
  description: 'Job ID',
476
458
  example: '1234',
477
459
  param: { id: 'jobRef' },
@@ -492,7 +474,7 @@ createDocument({
492
474
  });
493
475
 
494
476
  // or more verbose auto registration
495
- const jobId = z.string().meta({
477
+ const jobId = z.string().openapi({
496
478
  description: 'Job ID',
497
479
  example: '1234',
498
480
  param: { in: 'header', name: 'jobId', id: 'jobRef' },
@@ -508,8 +490,8 @@ createDocument({
508
490
  },
509
491
  });
510
492
 
511
- // or manual registration
512
- const otherJobId = z.string().meta({
493
+ // or manual registeration
494
+ const otherJobId = z.string().openapi({
513
495
  description: 'Job ID',
514
496
  example: '1234',
515
497
  param: { in: 'header', name: 'jobId' },
@@ -529,7 +511,7 @@ createDocument({
529
511
  Response headers can be similarly registered:
530
512
 
531
513
  ```typescript
532
- const header = z.string().meta({
514
+ const header = z.string().openapi({
533
515
  description: 'Job ID',
534
516
  example: '1234',
535
517
  header: { id: 'some-header' },
@@ -537,7 +519,7 @@ const header = z.string().meta({
537
519
 
538
520
  // or
539
521
 
540
- const jobIdHeader = z.string().meta({
522
+ const jobIdHeader = z.string().openapi({
541
523
  description: 'Job ID',
542
524
  example: '1234',
543
525
  });
@@ -633,121 +615,6 @@ createDocument({
633
615
  });
634
616
  ```
635
617
 
636
- #### Path Items
637
-
638
- Path Items can also be registered
639
-
640
- ```typescript
641
- const pathItem: ZodOpenApiPathItemObject = {
642
- id: 'some-path-item',
643
- get: {
644
- responses: {
645
- 200: {
646
- description: '200 OK',
647
- content: {
648
- 'application/json': {
649
- schema: z.object({ a: z.string() }),
650
- },
651
- },
652
- },
653
- },
654
- },
655
- };
656
-
657
- // or
658
-
659
- createDocument({
660
- components: {
661
- pathItems: {
662
- 'some-path-item': pathItem,
663
- },
664
- },
665
- });
666
- ```
667
-
668
- #### Security Schemes
669
-
670
- Security Schemes can be registered for authentication methods:
671
-
672
- ```typescript
673
- createDocument({
674
- components: {
675
- securitySchemes: {
676
- bearerAuth: {
677
- type: 'http',
678
- scheme: 'bearer',
679
- bearerFormat: 'JWT',
680
- description: 'JWT Authentication',
681
- },
682
- },
683
- },
684
- });
685
- ```
686
-
687
- #### Links
688
-
689
- Links can be registered to describe relationships between operations:
690
-
691
- ```typescript
692
- const link: ZodOpenApiLinkObject = {
693
- id: 'getUserById',
694
- operationId: 'getUser',
695
- parameters: {
696
- userId: '$request.path.id',
697
- },
698
- description: 'Link to get user by id',
699
- };
700
-
701
- // or
702
-
703
- createDocument({
704
- components: {
705
- links: {
706
- getUserById: {
707
- operationId: 'getUser',
708
- parameters: {
709
- userId: '$request.path.id',
710
- },
711
- description: 'Link to get user by id',
712
- },
713
- },
714
- },
715
- });
716
- ```
717
-
718
- #### Examples
719
-
720
- Examples can be registered to provide sample values for schemas:
721
-
722
- ```typescript
723
- const example: ZodOpenApiExampleObject = {
724
- id: 'userExample',
725
- summary: 'A sample user',
726
- value: {
727
- id: '123',
728
- name: 'Jane Doe',
729
- email: 'jane@example.com',
730
- },
731
- };
732
-
733
- // or
734
-
735
- createDocument({
736
- components: {
737
- examples: {
738
- userExample: {
739
- summary: 'A sample user',
740
- value: {
741
- id: '123',
742
- name: 'Jane Doe',
743
- email: 'jane@example.com',
744
- },
745
- },
746
- },
747
- },
748
- });
749
- ```
750
-
751
618
  ### Zod Types
752
619
 
753
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.
@@ -764,13 +631,13 @@ Output:
764
631
 
765
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()`.
766
633
 
767
- ```typescript
634
+ ```ts
768
635
  const schema = z.object({
769
636
  name: z.string(),
770
637
  });
771
638
  ```
772
639
 
773
- Input schemas (request bodies, parameters):
640
+ Input:
774
641
 
775
642
  ```json
776
643
  {
@@ -784,7 +651,7 @@ Input schemas (request bodies, parameters):
784
651
  }
785
652
  ```
786
653
 
787
- Output schemas (responses):
654
+ Output:
788
655
 
789
656
  ```json
790
657
  {
@@ -799,30 +666,25 @@ Output schemas (responses):
799
666
  }
800
667
  ```
801
668
 
802
- 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.
803
670
 
804
- 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.
805
674
 
806
675
  ```ts
807
676
  const schema = z
808
677
  .object({
809
678
  name: z.string(),
810
679
  })
811
- .meta({
812
- id: 'MyObject',
813
- outputId: 'MyObjectResponse', // Customize the output schema name
814
- });
680
+ .meta({ id: 'MyObject', outputId: 'MyObjectResponse' });
815
681
  ```
816
682
 
817
- 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.
818
-
819
- > **⚠️ Note:** If your registered schema contains dynamically created lazy components, they won't be reused between input and output schemas.
820
-
821
683
  ## Supported OpenAPI Versions
822
684
 
823
685
  Currently the following versions of OpenAPI are supported
824
686
 
825
- - `3.1.0` (minimum version)
687
+ - `3.1.0`
826
688
  - `3.1.1`
827
689
 
828
690
  Setting the `openapi` field will change how the some of the components are rendered.
@@ -864,10 +726,6 @@ See the library in use in the [examples](./examples/) folder.
864
726
 
865
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.
866
728
 
867
- ## Version Information
868
-
869
- For information about changes and migration from v4 to v5, see the [v5 migration guide](./docs/v5.md).
870
-
871
729
  ## Comparisons
872
730
 
873
731
  ### [@asteasolutions/zod-to-openapi](./docs/comparisons.md)
package/api/index.d.ts CHANGED
@@ -1 +1 @@
1
- export * from '../dist/api';
1
+ export * from "../dist/api";
package/dist/api.cjs ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const components = require("./components.chunk.cjs");
4
+ exports.createComponents = components.createComponents;
5
+ exports.createMediaTypeObject = components.createMediaTypeObject;
6
+ exports.createParameter = components.createParameter;
7
+ exports.createRegistry = components.createRegistry;
8
+ exports.unwrapZodObject = components.unwrapZodObject;
package/dist/api.d.mts CHANGED
@@ -1,11 +1,5 @@
1
- import { ComponentRegistry, Override, createComponents, createRegistry } from "./components-DkESnIB9.mjs";
2
- import { $ZodObject, $ZodType, $ZodTypes } from "zod/v4/core";
3
- import { core } from "zod/v4";
4
-
5
- //#region src/create/object.d.ts
6
- declare const unwrapZodObject: (zodType: $ZodTypes, io: "input" | "output", path: string[]) => $ZodObject;
7
- //#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 };
1
+ export { createComponents, createRegistry } from './create/components.js';
2
+ export { createMediaTypeObject } from './create/content.js';
3
+ export { createParameter } from './create/parameters.js';
4
+ export { unwrapZodObject } from './create/object.js';
5
+ export { Override, isAnyZodType } from './zod.js';
package/dist/api.d.ts CHANGED
@@ -1,11 +1,5 @@
1
- import { ComponentRegistry, Override, createComponents, createRegistry } from "./components-BLmIpmmY.js";
2
- import { $ZodObject, $ZodType, $ZodTypes } from "zod/v4/core";
3
- import { core } from "zod/v4";
4
-
5
- //#region src/create/object.d.ts
6
- declare const unwrapZodObject: (zodType: $ZodTypes, io: "input" | "output", path: string[]) => $ZodObject;
7
- //#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 };
1
+ export { createComponents, createRegistry } from './create/components.js';
2
+ export { createMediaTypeObject } from './create/content.js';
3
+ export { createParameter } from './create/parameters.js';
4
+ export { unwrapZodObject } from './create/object.js';
5
+ export { Override, isAnyZodType } from './zod.js';
package/dist/api.mjs CHANGED
@@ -1,3 +1,8 @@
1
- import { createComponents, createRegistry, isAnyZodType, unwrapZodObject } from "./components-Cblv9pY1.mjs";
2
-
3
- export { createComponents, createRegistry, isAnyZodType, unwrapZodObject };
1
+ import { createComponents, createMediaTypeObject, createParameter, createRegistry, unwrapZodObject } from "./components.chunk.mjs";
2
+ export {
3
+ createComponents,
4
+ createMediaTypeObject,
5
+ createParameter,
6
+ createRegistry,
7
+ unwrapZodObject
8
+ };