Skip to content

fix(zod): add metadata option #2163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/few-apples-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/openapi-ts': patch
---

fix(zod): add `metadata` option to generate additional metadata for documentation, code generation, AI structured outputs, form validation, and other purposes
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ layout: home

hero:
name: High-quality tools for interacting with APIs
tagline: Codegen for your TypeScript projects. Trusted over 1,250,000 times each month to generate reliable API clients and SDKs.
tagline: Codegen for your TypeScript projects. Trusted over 1,500,000 times each month to generate reliable API clients and SDKs.
actions:
- link: /openapi-ts/get-started
text: Get Started
Expand Down
2 changes: 1 addition & 1 deletion docs/openapi-ts/get-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { embedProject } from '../embed'
This package is in initial development. The interface might change before it becomes stable. We encourage you to leave feedback on [GitHub](https://github.com/hey-api/openapi-ts/issues).
:::

[@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts) is an OpenAPI to TypeScript codegen trusted over 1,250,000 times each month to generate reliable API clients and SDKs. The code is [MIT-licensed](/license) and free to use. Discover available features below or view our [roadmap](https://github.com/orgs/hey-api/discussions/1495) to learn what's coming next.
[@hey-api/openapi-ts](https://github.com/hey-api/openapi-ts) is an OpenAPI to TypeScript codegen trusted over 1,500,000 times each month to generate reliable API clients and SDKs. The code is [MIT-licensed](/license) and free to use. Discover available features below or view our [roadmap](https://github.com/orgs/hey-api/discussions/1495) to learn what's coming next.

### Demo

Expand Down
26 changes: 20 additions & 6 deletions docs/openapi-ts/plugins/zod.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,11 @@ Launch demo
In your [configuration](/openapi-ts/get-started), add `zod` to your plugins and you'll be ready to generate Zod artifacts. :tada:

```js
import { defaultPlugins } from '@hey-api/openapi-ts';

export default {
input: 'https://get.heyapi.dev/hey-api/backend',
output: 'src/client',
plugins: [
...defaultPlugins,
// ...other plugins
'@hey-api/client-fetch',
'zod', // [!code ++]
],
Expand All @@ -51,13 +49,11 @@ export default {
To automatically validate response data in your SDKs, set `sdk.validator` to `true`.

```js
import { defaultPlugins } from '@hey-api/openapi-ts';

export default {
input: 'https://get.heyapi.dev/hey-api/backend',
output: 'src/client',
plugins: [
...defaultPlugins,
// ...other plugins
'@hey-api/client-fetch',
'zod',
{
Expand Down Expand Up @@ -120,5 +116,23 @@ const zBar = z.object({
});
```

## Metadata

It's often useful to associate a schema with some additional metadata for documentation, code generation, AI structured outputs, form validation, and other purposes. If this is your use case, you can set `metadata` to `true` to generate additional metadata about schemas.

```js
export default {
input: 'https://get.heyapi.dev/hey-api/backend',
output: 'src/client',
plugins: [
// ...other plugins
{
metadata: true, // [!code ++]
name: 'zod',
},
],
};
```

<!--@include: ../../examples.md-->
<!--@include: ../../sponsors.md-->
14 changes: 14 additions & 0 deletions packages/openapi-ts-tests/test/3.1.x.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,20 @@ describe(`OpenAPI ${version}`, () => {
}),
description: 'generates validator schemas',
},
{
config: createConfig({
input: 'validators.yaml',
output: 'validators-metadata',
plugins: [
'valibot',
{
metadata: true,
name: 'zod',
},
],
}),
description: 'generates validator schemas with metadata',
},
{
config: createConfig({
input: 'validators-bigint-min-max.json',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// This file is auto-generated by @hey-api/openapi-ts

import * as v from 'valibot';

/**
* This is Bar schema.
*/
export const vBar: v.GenericSchema = v.object({
foo: v.optional(v.lazy(() => {
return vFoo;
}))
});

/**
* This is Foo schema.
*/
export const vFoo: v.GenericSchema = v.optional(v.union([
v.object({
foo: v.optional(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/))),
bar: v.optional(vBar),
baz: v.optional(v.array(v.lazy(() => {
return vFoo;
}))),
qux: v.optional(v.pipe(v.number(), v.integer(), v.gtValue(0)), 0)
}),
v.null()
]), null);

export const vBaz = v.optional(v.pipe(v.pipe(v.string(), v.regex(/foo\nbar/)), v.readonly()), 'baz');

/**
* This is Foo parameter.
*/
export const vFoo2 = v.string();

export const vFoo3 = v.object({
foo: v.optional(vBar)
});

export const vPatchFooData = v.object({
foo: v.optional(v.string())
});

/**
* This is Foo parameter.
*/
export const vPatchFooParameterFoo = v.string();

export const vPatchFooParameterBar = vBar;

export const vPatchFooParameterBaz = v.object({
baz: v.optional(v.string())
});

export const vPatchFooParameterQux = v.pipe(v.string(), v.isoDate());

export const vPatchFooParameterQuux = v.pipe(v.string(), v.isoDateTime());

export const vPostFooData = vFoo3;
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// This file is auto-generated by @hey-api/openapi-ts

import { z } from 'zod';

/**
* This is Bar schema.
*/
export const zBar: z.AnyZodObject = z.object({
foo: z.lazy(() => {
return zFoo;
}).optional()
}).describe('This is Bar schema.');

/**
* This is Foo schema.
*/
export const zFoo: z.ZodTypeAny = z.union([
z.object({
foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).describe('This is foo property.').optional(),
bar: zBar.optional(),
baz: z.array(z.lazy(() => {
return zFoo;
})).describe('This is baz property.').optional(),
qux: z.number().int().gt(0).describe('This is qux property.').optional().default(0)
}),
z.null()
]).default(null);

export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz');

/**
* This is Foo parameter.
*/
export const zFoo2 = z.string().describe('This is Foo parameter.');

export const zFoo3 = z.object({
foo: zBar.optional()
});

export const zPatchFooData = z.object({
foo: z.string().optional()
});

/**
* This is Foo parameter.
*/
export const zPatchFooParameterFoo = z.string().describe('This is Foo parameter.');

export const zPatchFooParameterBar = zBar;

export const zPatchFooParameterBaz = z.object({
baz: z.string().optional()
});

export const zPatchFooParameterQux = z.string().date();

export const zPatchFooParameterQuux = z.string().datetime();

export const zPostFooData = zFoo3;
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@

import * as v from 'valibot';

/**
* This is Bar schema.
*/
export const vBar: v.GenericSchema = v.object({
foo: v.optional(v.lazy(() => {
return vFoo;
}))
});

/**
* This is Foo schema.
*/
export const vFoo: v.GenericSchema = v.optional(v.union([
v.object({
foo: v.optional(v.pipe(v.string(), v.regex(/^\d{3}-\d{2}-\d{4}$/))),
Expand All @@ -23,7 +29,7 @@ export const vFoo: v.GenericSchema = v.optional(v.union([
export const vBaz = v.optional(v.pipe(v.pipe(v.string(), v.regex(/foo\nbar/)), v.readonly()), 'baz');

/**
* aaaaa
* This is Foo parameter.
*/
export const vFoo2 = v.string();

Expand All @@ -36,7 +42,7 @@ export const vPatchFooData = v.object({
});

/**
* aaaaa
* This is Foo parameter.
*/
export const vPatchFooParameterFoo = v.string();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@

import { z } from 'zod';

/**
* This is Bar schema.
*/
export const zBar: z.AnyZodObject = z.object({
foo: z.lazy(() => {
return zFoo;
}).optional()
});

/**
* This is Foo schema.
*/
export const zFoo: z.ZodTypeAny = z.union([
z.object({
foo: z.string().regex(/^\d{3}-\d{2}-\d{4}$/).optional(),
Expand All @@ -23,7 +29,7 @@ export const zFoo: z.ZodTypeAny = z.union([
export const zBaz = z.string().regex(/foo\nbar/).readonly().default('baz');

/**
* aaaaa
* This is Foo parameter.
*/
export const zFoo2 = z.string();

Expand All @@ -36,7 +42,7 @@ export const zPatchFooData = z.object({
});

/**
* aaaaa
* This is Foo parameter.
*/
export const zPatchFooParameterFoo = z.string();

Expand Down
12 changes: 4 additions & 8 deletions packages/openapi-ts-tests/test/openapi-ts.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,7 @@ export default defineConfig(() => {
// 'invalid',
// 'servers-entry.yaml',
// ),
path: path.resolve(
__dirname,
'spec',
'3.1.x',
'object-property-names.yaml',
),
path: path.resolve(__dirname, 'spec', '3.1.x', 'validators.yaml'),
// path: 'http://localhost:4000/',
// path: 'https://get.heyapi.dev/',
// path: 'https://get.heyapi.dev/hey-api/backend?branch=main&version=1.0.0',
Expand Down Expand Up @@ -150,12 +145,13 @@ export default defineConfig(() => {
{
// comments: false,
// exportFromIndex: true,
// name: 'valibot',
name: 'valibot',
},
{
// comments: false,
// exportFromIndex: true,
// name: 'zod',
metadata: true,
name: 'zod',
},
],
// useOptions: false,
Expand Down
7 changes: 6 additions & 1 deletion packages/openapi-ts-tests/test/spec/3.1.x/validators.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ paths:
components:
parameters:
Foo:
description: aaaaa
description: 'This is Foo parameter.'
name: foo
in: query
required: false
Expand All @@ -72,24 +72,29 @@ components:
schemas:
Foo:
default: null
description: 'This is Foo schema.'
properties:
foo:
description: 'This is foo property.'
pattern: ^\d{3}-\d{2}-\d{4}$
type: string
bar:
$ref: '#/components/schemas/Bar'
baz:
description: 'This is baz property.'
items:
$ref: '#/components/schemas/Foo'
type: array
qux:
description: 'This is qux property.'
default: 0
exclusiveMinimum: 0
type: integer
type:
- object
- 'null'
Bar:
description: 'This is Bar schema.'
properties:
foo:
$ref: '#/components/schemas/Foo'
Expand Down
1 change: 1 addition & 0 deletions packages/openapi-ts/src/plugins/zod/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const defaultConfig: Plugin.Config<Config> = {
_tags: ['validator'],
comments: true,
exportFromIndex: false,
metadata: false,
name: 'zod',
output: 'zod',
};
Expand Down
Loading