Skip to content

Commit 7551a64

Browse files
committed
feat(client): add requestValidator option
1 parent d7f08be commit 7551a64

File tree

35 files changed

+1060
-415
lines changed

35 files changed

+1060
-415
lines changed

examples/openapi-ts-fetch/src/client/client/client.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ export const createClient = (config: Config = {}): Client => {
4646
});
4747
}
4848

49+
if (opts.requestValidator) {
50+
await opts.requestValidator(opts);
51+
}
52+
4953
if (opts.body && opts.bodySerializer) {
5054
opts.body = opts.bodySerializer(opts.body);
5155
}
@@ -103,16 +107,24 @@ export const createClient = (config: Config = {}): Client => {
103107
? getParseAs(response.headers.get('Content-Type'))
104108
: opts.parseAs) ?? 'json';
105109

106-
if (parseAs === 'stream') {
107-
return opts.responseStyle === 'data'
108-
? response.body
109-
: {
110-
data: response.body,
111-
...result,
112-
};
110+
let data: any;
111+
switch (parseAs) {
112+
case 'arrayBuffer':
113+
case 'blob':
114+
case 'formData':
115+
case 'json':
116+
case 'text':
117+
data = await response[parseAs]();
118+
break;
119+
case 'stream':
120+
return opts.responseStyle === 'data'
121+
? response.body
122+
: {
123+
data: response.body,
124+
...result,
125+
};
113126
}
114127

115-
let data = await response[parseAs]();
116128
if (parseAs === 'json') {
117129
if (opts.responseValidator) {
118130
await opts.responseValidator(data);

examples/openapi-ts-fetch/src/client/client/types.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,14 @@ export interface Config<T extends ClientOptions = ClientOptions>
3333
*
3434
* @default 'auto'
3535
*/
36-
parseAs?: Exclude<keyof Body, 'body' | 'bodyUsed'> | 'auto' | 'stream';
36+
parseAs?:
37+
| 'arrayBuffer'
38+
| 'auto'
39+
| 'blob'
40+
| 'formData'
41+
| 'json'
42+
| 'stream'
43+
| 'text';
3744
/**
3845
* Should we return only data or multiple fields (data, error, response, etc.)?
3946
*

examples/openapi-ts-fetch/src/client/client/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ export const getParseAs = (
182182
if (cleanContent.startsWith('text/')) {
183183
return 'text';
184184
}
185+
186+
return;
185187
};
186188

187189
export const setAuthParams = async ({

examples/openapi-ts-fetch/src/client/core/bodySerializer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const formDataBodySerializer = {
5757

5858
export const jsonBodySerializer = {
5959
bodySerializer: <T>(body: T) =>
60-
JSON.stringify(body, (key, value) =>
60+
JSON.stringify(body, (_key, value) =>
6161
typeof value === 'bigint' ? value.toString() : value,
6262
),
6363
};

examples/openapi-ts-fetch/src/client/core/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,12 @@ export interface Config {
8484
* {@link https://swagger.io/docs/specification/serialization/#query View examples}
8585
*/
8686
querySerializer?: QuerySerializer | QuerySerializerOptions;
87+
/**
88+
* A function validating request data. This is useful if you want to ensure
89+
* the request conforms to the desired shape, so it can be safely sent to
90+
* the server.
91+
*/
92+
requestValidator?: (data: unknown) => Promise<unknown>;
8793
/**
8894
* A function transforming response data before it's returned. This is useful
8995
* for post-processing data, e.g. converting ISO strings into Date objects.

examples/openapi-ts-fetch/src/client/types.gen.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ export type LoginUserResponses = {
560560
/**
561561
* successful operation
562562
*/
563-
200: Blob | File;
563+
200: string;
564564
};
565565

566566
export type LoginUserResponse = LoginUserResponses[keyof LoginUserResponses];

examples/openapi-ts-sample/openapi-ts.config.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ export default defineConfig({
1414
runtimeConfigPath: './src/hey-api.ts',
1515
},
1616
'@hey-api/schemas',
17-
'@hey-api/sdk',
17+
{
18+
name: '@hey-api/sdk',
19+
validator: 'zod',
20+
},
1821
{
1922
enums: 'javascript',
2023
name: '@hey-api/typescript',

examples/openapi-ts-sample/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
"@radix-ui/react-icons": "1.3.2",
1717
"@radix-ui/themes": "3.1.6",
1818
"react": "19.0.0",
19-
"react-dom": "19.0.0"
19+
"react-dom": "19.0.0",
20+
"valibot": "1.1.0",
21+
"zod": "3.23.8"
2022
},
2123
"devDependencies": {
2224
"@config/vite-base": "workspace:*",

examples/openapi-ts-sample/src/App.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,18 @@ import {
99
Section,
1010
} from '@radix-ui/themes';
1111

12-
// @ts-expect-error
13-
import { postFoo } from './client/sdk.gen';
12+
import { getPetById } from './client/sdk.gen';
1413

1514
function App() {
1615
const onClick = async () => {
17-
postFoo({
18-
body: {
19-
foo: [[1, 2]],
16+
const response = await getPetById({
17+
path: {
18+
// @ts-expect-error
19+
foo: 3,
20+
petId: 3,
2021
},
2122
});
23+
console.log(response);
2224
};
2325

2426
return (

examples/openapi-ts-sample/src/client/client/client.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ export const createClient = (config: Config = {}): Client => {
4646
});
4747
}
4848

49+
if (opts.requestValidator) {
50+
await opts.requestValidator(opts);
51+
}
52+
4953
if (opts.body && opts.bodySerializer) {
5054
opts.body = opts.bodySerializer(opts.body);
5155
}
@@ -103,16 +107,24 @@ export const createClient = (config: Config = {}): Client => {
103107
? getParseAs(response.headers.get('Content-Type'))
104108
: opts.parseAs) ?? 'json';
105109

106-
if (parseAs === 'stream') {
107-
return opts.responseStyle === 'data'
108-
? response.body
109-
: {
110-
data: response.body,
111-
...result,
112-
};
110+
let data: any;
111+
switch (parseAs) {
112+
case 'arrayBuffer':
113+
case 'blob':
114+
case 'formData':
115+
case 'json':
116+
case 'text':
117+
data = await response[parseAs]();
118+
break;
119+
case 'stream':
120+
return opts.responseStyle === 'data'
121+
? response.body
122+
: {
123+
data: response.body,
124+
...result,
125+
};
113126
}
114127

115-
let data = await response[parseAs]();
116128
if (parseAs === 'json') {
117129
if (opts.responseValidator) {
118130
await opts.responseValidator(data);

0 commit comments

Comments
 (0)