Skip to content

feat(sdk): add request validators #2227

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 8 commits into from
Jun 24, 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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .changeset/clever-jeans-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@hey-api/openapi-ts': minor
---

refactor(plugin): add `DefinePlugin` utility types

### Updated Plugin API

Please refer to the [custom plugin](https://heyapi.dev/openapi-ts/plugins/custom) tutorial for the latest guide.
26 changes: 26 additions & 0 deletions .changeset/quick-hotels-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
'@hey-api/openapi-ts': minor
---

feat(sdk): update `validator` option

### Updated `sdk.validator` option

Clients can now validate both request and response data. As a result, passing a boolean or string to `validator` will control both of these options. To preserve the previous behavior, set `validator.request` to `false` and `validator.response` to your previous configuration.

```js
export default {
input: 'https://get.heyapi.dev/hey-api/backend',
output: 'src/client',
plugins: [
// ...other plugins
{
name: '@hey-api/sdk',
validator: {
request: false,
response: true,
},
},
],
};
```
5 changes: 5 additions & 0 deletions .changeset/real-horses-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/openapi-ts': patch
---

fix(client): add requestValidator option
29 changes: 29 additions & 0 deletions docs/openapi-ts/migrating.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,35 @@ This config option is deprecated and will be removed in favor of [clients](./cli

This config option is deprecated and will be removed.

## v0.77.0

### Updated `sdk.validator` option

Clients can now validate both request and response data. As a result, passing a boolean or string to `validator` will control both of these options. To preserve the previous behavior, set `validator.request` to `false` and `validator.response` to your previous configuration.

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

### Updated Plugin API

Please refer to the [custom plugin](/openapi-ts/plugins/custom) tutorial for the latest guide.

## v0.76.0

### Single Valibot schema per request
Expand Down
78 changes: 78 additions & 0 deletions docs/openapi-ts/output/sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,83 @@ client.post({

:::

## Validators

There are two ways to configure validators. If you only want to add validators to your SDKs, set `sdk.validator` to a validator plugin name. This will implicitly add the selected plugin with default values.

For a more granular approach, add a validator plugin and set `sdk.validator` to the plugin name or `true` to automatically select a plugin. Until you customize the validator plugin, both approaches will produce the same default output.

::: code-group

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

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

:::

You can choose to validate only requests or responses.

::: code-group

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

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

:::

Learn more about available validators on the [Validators](/openapi-ts/validators) page.

<!--@include: ../../examples.md-->
<!--@include: ../../sponsors.md-->
38 changes: 16 additions & 22 deletions docs/openapi-ts/plugins/custom.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ We recommend following the design pattern of the native plugins. You can browse

```ts [index.ts]
export { defaultConfig, defineConfig } from './config';
export type { Config } from './types';
export type { MyPlugin } from './types';
```

:::
Expand All @@ -31,7 +31,9 @@ export type { Config } from './types';
::: code-group

```ts [types.d.ts]
export interface Config {
import type { DefinePlugin } from '@hey-api/openapi-ts';

export type Config = {
/**
* Plugin name. Must be unique.
*/
Expand All @@ -48,45 +50,39 @@ export interface Config {
* @default false
*/
myOption?: boolean;
}
};

export type MyPlugin = DefinePlugin<Config>;
```

:::

## Configuration

::: tip
Reserved fields are prefixed with an underscore and are not exposed to the user.
:::

`config.ts` contains the runtime configuration for your plugin. It must implement the `Config` interface we created above and define `handler()` and `handlerLegacy()` functions from the `Plugin.Config` interface.
`config.ts` contains the runtime configuration for your plugin. It must implement the `MyPlugin` interface we created above and define the `handler()` function from the `MyPlugin['Config']` interface.

::: code-group

```ts [config.ts]
import type { Plugin } from '@hey-api/openapi-ts';
import { definePluginConfig } from '@hey-api/openapi-ts';

import { handler } from './plugin';
import type { Config } from './types';
import type { MyPlugin } from './types';

export const defaultConfig: Plugin.Config<Config> = {
export const defaultConfig: MyPlugin['Config'] = {
config: {
myOption: false, // implements default value from types
},
dependencies: ['@hey-api/typescript'],
handler,
handlerLegacy: () => {},
name: 'my-plugin',
output: 'my-plugin',
};

/**
* Type helper for `my-plugin` plugin, returns {@link Plugin.Config} object
*/
export const defineConfig: Plugin.DefineConfig<Config> = (config) => ({
...defaultConfig,
...config,
});
export const defineConfig = definePluginConfig(defaultConfig);
```

:::
Expand All @@ -106,11 +102,9 @@ Notice we defined `handler` in our `config.ts` file. This method is responsible
::: code-group

```ts [plugin.ts]
import type { Plugin } from '@hey-api/openapi-ts';

import type { Config } from './types';
import type { MyPlugin } from './types';

export const handler: Plugin.Handler<Config> = ({ plugin }) => {
export const handler: MyPlugin['Handler'] = ({ plugin }) => {
// create an output file. it will not be
// generated until it contains nodes
const file = plugin.createFile({
Expand Down Expand Up @@ -149,9 +143,9 @@ export const handler: Plugin.Handler<Config> = ({ plugin }) => {

:::

### Legacy
### Legacy Handler

Notice we defined `handlerLegacy` in our `config.ts` file. This method is responsible for generating the actual output when using the legacy parser. We do not recommend implementing this method unless you must use the legacy parser. You can use one of our [`plugin-legacy.ts`](https://github.com/hey-api/openapi-ts/blob/main/packages/openapi-ts/src/plugins/%40hey-api/typescript/plugin-legacy.ts) files as an inspiration for potential implementation.
You can also define an optional `handlerLegacy` function in `config.ts`. This method is responsible for generating the output when using the legacy parser. We do not recommend implementing this method unless you must use the legacy parser. You can use one of our [`plugin-legacy.ts`](https://github.com/hey-api/openapi-ts/blob/main/packages/openapi-ts/src/plugins/%40hey-api/typescript/plugin-legacy.ts) files as an inspiration for potential implementation.

## Usage

Expand Down
5 changes: 3 additions & 2 deletions docs/openapi-ts/plugins/valibot.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default {

### SDKs

To automatically validate response data in your SDKs, set `sdk.validator` to `true`.
To add data validators to your SDKs, set `sdk.validator` to `true`.

```js
export default {
Expand All @@ -62,6 +62,8 @@ export default {
};
```

Learn more about data validators in your SDKs on the [SDKs](/openapi-ts/output/sdk#validators) page.

## Output

The Valibot plugin will generate the following artifacts, depending on the input specification.
Expand All @@ -78,7 +80,6 @@ const vData = v.object({
bar: v.optional(v.union([v.number(), v.null()])),
}),
),
headers: v.optional(v.never()),
path: v.object({
baz: v.string(),
}),
Expand Down
5 changes: 3 additions & 2 deletions docs/openapi-ts/plugins/zod.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default {

### SDKs

To automatically validate response data in your SDKs, set `sdk.validator` to `true`.
To add data validators to your SDKs, set `sdk.validator` to `true`.

```js
export default {
Expand All @@ -62,6 +62,8 @@ export default {
};
```

Learn more about data validators in your SDKs on the [SDKs](/openapi-ts/output/sdk#validators) page.

## Output

The Zod plugin will generate the following artifacts, depending on the input specification.
Expand All @@ -78,7 +80,6 @@ const zData = z.object({
bar: z.union([z.number(), z.null()]).optional(),
})
.optional(),
headers: z.never().optional(),
path: z.object({
baz: z.string(),
}),
Expand Down
43 changes: 5 additions & 38 deletions docs/openapi-ts/validators.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ There are times when you cannot blindly trust the server to return the correct d

Whatever your reason to use validators might be, you can rest assured that you're working with the correct data.

## Features

- seamless integration with `@hey-api/openapi-ts` ecosystem
- schemas for requests, responses, and reusable definitions

## Options

Hey API natively supports the following validators.
Expand All @@ -23,43 +28,5 @@ Hey API natively supports the following validators.

Don't see your validator? Let us know your interest by [opening an issue](https://github.com/hey-api/openapi-ts/issues).

## Installation

There are two ways to generate validators. If you only need response validation in your SDKs, set `sdk.validator` to the desired value. For a more granular approach, add your validator to plugins and set `sdk.validator` to `true`.

::: code-group

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

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

:::

<!--@include: ../examples.md-->
<!--@include: ../sponsors.md-->
Loading
Loading