Skip to content

Commit 2296b1e

Browse files
committed
feat(sdk): support setting validators per operation
1 parent bb30d6e commit 2296b1e

File tree

7 files changed

+109
-176
lines changed

7 files changed

+109
-176
lines changed

dev/openapi-ts.config.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -272,11 +272,13 @@ export default defineConfig(() => {
272272
// signature: 'object',
273273
// transformer: '@hey-api/transformers',
274274
// transformer: true,
275-
// validator: true,
276-
// validator: {
277-
// request: 'zod',
278-
// response: 'zod',
275+
// validator(operation) {
276+
// return 'zod';
279277
// },
278+
validator: {
279+
request: 'valibot',
280+
response: 'zod',
281+
},
280282
'~hooks': {
281283
symbols: {
282284
// getFilePath: (symbol) => {
@@ -339,7 +341,7 @@ export default defineConfig(() => {
339341
},
340342
},
341343
{
342-
name: 'arktype',
344+
// name: 'arktype',
343345
// types: {
344346
// infer: true,
345347
// },

packages/openapi-ts/src/plugins/@hey-api/sdk/config.ts

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { definePluginConfig } from '~/plugins/shared/utils/config';
2+
import type { PluginValidatorNames } from '~/plugins/types';
23

34
import { Api } from './api';
45
import { handler } from './plugin';
@@ -47,32 +48,40 @@ export const defaultConfig: HeyApiSdkPlugin['Config'] = {
4748
plugin.config.transformer = false;
4849
}
4950

50-
if (typeof plugin.config.validator !== 'object') {
51-
plugin.config.validator = {
52-
request: plugin.config.validator,
53-
response: plugin.config.validator,
54-
};
55-
}
56-
57-
if (plugin.config.validator.request) {
58-
if (typeof plugin.config.validator.request === 'boolean') {
59-
plugin.config.validator.request = context.pluginByTag('validator');
51+
const { validator } = plugin.config;
52+
plugin.config.validator = ((operation) => {
53+
if (typeof validator === 'boolean') {
54+
const validatorPlugin = validator
55+
? context.pluginByTag('validator')
56+
: undefined;
57+
const validatorValue = validatorPlugin
58+
? (validatorPlugin as PluginValidatorNames)
59+
: false;
60+
return {
61+
request: validatorValue,
62+
response: validatorValue,
63+
};
6064
}
6165

62-
plugin.dependencies.add(plugin.config.validator.request!);
63-
} else {
64-
plugin.config.validator.request = false;
65-
}
66+
if (typeof validator === 'string') {
67+
return {
68+
request: validator,
69+
response: validator,
70+
};
71+
}
6672

67-
if (plugin.config.validator.response) {
68-
if (typeof plugin.config.validator.response === 'boolean') {
69-
plugin.config.validator.response = context.pluginByTag('validator');
73+
if (typeof validator === 'function') {
74+
const result = validator(operation);
75+
if (typeof result === 'object') {
76+
// result.request
77+
}
7078
}
7179

72-
plugin.dependencies.add(plugin.config.validator.response!);
73-
} else {
74-
plugin.config.validator.response = false;
75-
}
80+
return {
81+
request: false,
82+
response: false,
83+
};
84+
}) satisfies HeyApiSdkPlugin['Types']['resolvedConfig']['validator'];
7685

7786
if (plugin.config.instance) {
7887
if (typeof plugin.config.instance !== 'string') {
@@ -91,6 +100,7 @@ export const defaultConfig: HeyApiSdkPlugin['Config'] = {
91100
}
92101
}
93102
},
103+
tags: ['sdk'],
94104
};
95105

96106
/**

packages/openapi-ts/src/plugins/@hey-api/sdk/shared/operation.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import type { HeyApiSdkPlugin } from '../types';
1919
import { operationAuth } from './auth';
2020
import { nuxtTypeComposable, nuxtTypeDefault } from './constants';
2121
import { getSignatureParameters } from './signature';
22-
import { createRequestValidator, createResponseValidator } from './validator';
22+
import { createValidators } from './validator';
2323

2424
interface ClassNameEntry {
2525
/**
@@ -502,11 +502,11 @@ export const operationStatements = ({
502502
});
503503
}
504504

505-
const requestValidator = createRequestValidator({ operation, plugin });
506-
if (requestValidator) {
505+
const validators = createValidators({ operation, plugin });
506+
if (validators.request) {
507507
requestOptions.push({
508508
key: 'requestValidator',
509-
value: requestValidator,
509+
value: validators.request,
510510
});
511511
}
512512

@@ -553,11 +553,10 @@ export const operationStatements = ({
553553
}
554554
}
555555

556-
const responseValidator = createResponseValidator({ operation, plugin });
557-
if (responseValidator) {
556+
if (validators.response) {
558557
requestOptions.push({
559558
key: 'responseValidator',
560-
value: responseValidator,
559+
value: validators.response,
561560
});
562561
}
563562

packages/openapi-ts/src/plugins/@hey-api/sdk/shared/validator.ts

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,39 @@ import type { IR } from '~/ir/types';
44

55
import type { HeyApiSdkPlugin } from '../types';
66

7-
interface ValidatorProps {
8-
operation: IR.OperationObject;
9-
plugin: HeyApiSdkPlugin['Instance'];
10-
}
11-
12-
export const createRequestValidator = ({
13-
operation,
14-
plugin,
15-
}: ValidatorProps): ts.ArrowFunction | undefined => {
16-
if (!plugin.config.validator.request) return;
17-
18-
const validator = plugin.getPluginOrThrow(plugin.config.validator.request);
19-
if (!validator.api.createRequestValidator) return;
20-
21-
return validator.api.createRequestValidator({
22-
operation,
23-
// @ts-expect-error
24-
plugin: validator,
25-
});
7+
type Validators = {
8+
request?: ts.ArrowFunction;
9+
response?: ts.ArrowFunction;
2610
};
2711

28-
export const createResponseValidator = ({
12+
export const createValidators = ({
2913
operation,
3014
plugin,
31-
}: ValidatorProps): ts.ArrowFunction | undefined => {
32-
if (!plugin.config.validator.response) return;
33-
34-
const validator = plugin.getPluginOrThrow(plugin.config.validator.response);
35-
if (!validator.api.createResponseValidator) return;
36-
37-
return validator.api.createResponseValidator({
38-
operation,
39-
// @ts-expect-error
40-
plugin: validator,
41-
});
15+
}: {
16+
operation: IR.OperationObject;
17+
plugin: HeyApiSdkPlugin['Instance'];
18+
}): Validators => {
19+
const validators: Validators = {};
20+
const values = plugin.config.validator(operation);
21+
if (values.request) {
22+
const validator = plugin.getPluginOrThrow(values.request);
23+
if (validator.api.createRequestValidator) {
24+
validators.request = validator.api.createRequestValidator({
25+
operation,
26+
// @ts-expect-error
27+
plugin: validator,
28+
});
29+
}
30+
}
31+
if (values.response) {
32+
const validator = plugin.getPluginOrThrow(values.response);
33+
if (validator.api.createResponseValidator) {
34+
validators.response = validator.api.createResponseValidator({
35+
operation,
36+
// @ts-expect-error
37+
plugin: validator,
38+
});
39+
}
40+
}
41+
return validators;
4242
};

packages/openapi-ts/src/plugins/@hey-api/sdk/types.d.ts

Lines changed: 33 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,34 @@ import type { StringName } from '~/types/case';
55

66
import type { IApi } from './api';
77

8+
type ValidatorValue = PluginValidatorNames | boolean;
9+
type ValidatorResult =
10+
| ValidatorValue
11+
| {
12+
/**
13+
* Validate request data against schema before sending.
14+
*
15+
* Can be a validator plugin name or boolean (true to auto-select, false
16+
* to disable).
17+
*
18+
* @default false
19+
*/
20+
request?:
21+
| ValidatorValue
22+
| ((operation: IR.OperationObject) => ValidatorValue);
23+
/**
24+
* Validate response data against schema before returning.
25+
*
26+
* Can be a validator plugin name or boolean (true to auto-select, false
27+
* to disable).
28+
*
29+
* @default false
30+
*/
31+
response?:
32+
| ValidatorValue
33+
| ((operation: IR.OperationObject) => ValidatorValue);
34+
};
35+
836
export type UserConfig = Plugin.Name<'@hey-api/sdk'> &
937
Plugin.Hooks & {
1038
/**
@@ -137,50 +165,18 @@ export type UserConfig = Plugin.Name<'@hey-api/sdk'> &
137165
* @default false
138166
*/
139167
validator?:
140-
| PluginValidatorNames
141-
| boolean
142-
| {
143-
/**
144-
* Validate request data against schema before sending.
145-
*
146-
* Can be a validator plugin name or boolean (true to auto-select, false
147-
* to disable).
148-
*
149-
* @default false
150-
*/
151-
request?: PluginValidatorNames | boolean;
152-
/**
153-
* Validate response data against schema before returning.
154-
*
155-
* Can be a validator plugin name or boolean (true to auto-select, false
156-
* to disable).
157-
*
158-
* @default false
159-
*/
160-
response?: PluginValidatorNames | boolean;
161-
};
168+
| ValidatorResult
169+
| ((operation: IR.OperationObject) => ValidatorResult);
162170

163171
// DEPRECATED OPTIONS BELOW
164172

165-
/**
166-
* **This feature works only with the legacy parser**
167-
*
168-
* Filter endpoints to be included in the generated SDK. The provided
169-
* string should be a regular expression where matched results will be
170-
* included in the output. The input pattern this string will be tested
171-
* against is `{method} {path}`. For example, you can match
172-
* `POST /api/v1/foo` with `^POST /api/v1/foo$`.
173-
*
174-
* @deprecated
175-
*/
176-
// eslint-disable-next-line typescript-sort-keys/interface
177-
filter?: string;
178173
/**
179174
* Define shape of returned value from service calls
180175
*
181176
* @deprecated
182177
* @default 'body'
183178
*/
179+
// eslint-disable-next-line typescript-sort-keys/interface
184180
response?: 'body' | 'response';
185181
};
186182

@@ -303,7 +299,7 @@ export type Config = Plugin.Name<'@hey-api/sdk'> &
303299
* to a desired shape. However, validation adds runtime overhead, so it's
304300
* not recommended to use unless absolutely necessary.
305301
*/
306-
validator: {
302+
validator: (operation: IR.OperationObject) => {
307303
/**
308304
* The validator plugin to use for request validation, or false to disable.
309305
*
@@ -320,25 +316,13 @@ export type Config = Plugin.Name<'@hey-api/sdk'> &
320316

321317
// DEPRECATED OPTIONS BELOW
322318

323-
/**
324-
* **This feature works only with the legacy parser**
325-
*
326-
* Filter endpoints to be included in the generated SDK. The provided
327-
* string should be a regular expression where matched results will be
328-
* included in the output. The input pattern this string will be tested
329-
* against is `{method} {path}`. For example, you can match
330-
* `POST /api/v1/foo` with `^POST /api/v1/foo$`.
331-
*
332-
* @deprecated
333-
*/
334-
// eslint-disable-next-line typescript-sort-keys/interface
335-
filter?: string;
336319
/**
337320
* Define shape of returned value from service calls
338321
*
339322
* @deprecated
340323
* @default 'body'
341324
*/
325+
// eslint-disable-next-line typescript-sort-keys/interface
342326
response: 'body' | 'response';
343327
};
344328

0 commit comments

Comments
 (0)