tangled
alpha
login
or
join now
mokkenstorm.dev
/
openapi-ts
0
fork
atom
fork of hey-api/openapi-ts because I need some additional things
0
fork
atom
overview
issues
pulls
pipelines
chore: add transformer and validator
Lubos
1 year ago
848f34ce
ca013b35
+417
-173
12 changed files
expand all
collapse all
unified
split
examples
openapi-ts-nuxt
client
sdk.gen.ts
transformers.gen.ts
types.gen.ts
zod.gen.ts
components
home.vue
openapi-ts.config.ts
package.json
packages
client-nuxt
src
__tests__
utils.test.ts
index.ts
openapi-ts
src
plugins
@hey-api
sdk
plugin.ts
zod
plugin.ts
pnpm-lock.yaml
+60
examples/openapi-ts-nuxt/client/sdk.gen.ts
···
7
7
type Options,
8
8
} from '@hey-api/client-nuxt';
9
9
10
10
+
import {
11
11
+
addPetResponseTransformer,
12
12
+
createUserResponseTransformer,
13
13
+
findPetsByStatusResponseTransformer,
14
14
+
findPetsByTagsResponseTransformer,
15
15
+
getOrderByIdResponseTransformer,
16
16
+
getPetByIdResponseTransformer,
17
17
+
getUserByNameResponseTransformer,
18
18
+
placeOrderResponseTransformer,
19
19
+
updatePetResponseTransformer,
20
20
+
} from './transformers.gen';
10
21
import type {
11
22
AddPetData,
12
23
AddPetResponse,
···
41
52
UploadFileData,
42
53
UploadFileResponse,
43
54
} from './types.gen';
55
55
+
import {
56
56
+
zAddPetResponse,
57
57
+
zCreateUserResponse,
58
58
+
zCreateUsersWithListInputResponse,
59
59
+
zFindPetsByStatusResponse,
60
60
+
zFindPetsByTagsResponse,
61
61
+
zGetInventoryResponse,
62
62
+
zGetOrderByIdResponse,
63
63
+
zGetPetByIdResponse,
64
64
+
zGetUserByNameResponse,
65
65
+
zLoginUserResponse,
66
66
+
zPlaceOrderResponse,
67
67
+
zUpdatePetResponse,
68
68
+
zUploadFileResponse,
69
69
+
} from './zod.gen';
44
70
45
71
export const client = createClient(createConfig());
46
72
···
57
83
'Content-Type': 'application/json',
58
84
...options?.headers,
59
85
},
86
86
+
responseTransformer: addPetResponseTransformer,
87
87
+
responseValidator: async (data) => await zAddPetResponse.parseAsync(data),
60
88
url: '/pet',
61
89
});
62
90
···
73
101
'Content-Type': 'application/json',
74
102
...options?.headers,
75
103
},
104
104
+
responseTransformer: updatePetResponseTransformer,
105
105
+
responseValidator: async (data) =>
106
106
+
await zUpdatePetResponse.parseAsync(data),
76
107
url: '/pet',
77
108
});
78
109
···
89
120
unknown
90
121
>({
91
122
...options,
123
123
+
responseTransformer: findPetsByStatusResponseTransformer,
124
124
+
responseValidator: async (data) =>
125
125
+
await zFindPetsByStatusResponse.parseAsync(data),
92
126
url: '/pet/findByStatus',
93
127
});
94
128
···
102
136
(options?.client ?? client).get<TComposable, FindPetsByTagsResponse, unknown>(
103
137
{
104
138
...options,
139
139
+
responseTransformer: findPetsByTagsResponseTransformer,
140
140
+
responseValidator: async (data) =>
141
141
+
await zFindPetsByTagsResponse.parseAsync(data),
105
142
url: '/pet/findByTags',
106
143
},
107
144
);
···
126
163
) =>
127
164
(options?.client ?? client).get<TComposable, GetPetByIdResponse, unknown>({
128
165
...options,
166
166
+
responseTransformer: getPetByIdResponseTransformer,
167
167
+
responseValidator: async (data) =>
168
168
+
await zGetPetByIdResponse.parseAsync(data),
129
169
security: [
130
170
{
131
171
name: 'api_key',
···
158
198
'Content-Type': 'application/octet-stream',
159
199
...options?.headers,
160
200
},
201
201
+
responseValidator: async (data) =>
202
202
+
await zUploadFileResponse.parseAsync(data),
161
203
url: '/pet/{petId}/uploadImage',
162
204
});
163
205
···
170
212
) =>
171
213
(options?.client ?? client).get<TComposable, GetInventoryResponse, unknown>({
172
214
...options,
215
215
+
responseValidator: async (data) =>
216
216
+
await zGetInventoryResponse.parseAsync(data),
173
217
security: [
174
218
{
175
219
name: 'api_key',
···
192
236
'Content-Type': 'application/json',
193
237
...options?.headers,
194
238
},
239
239
+
responseTransformer: placeOrderResponseTransformer,
240
240
+
responseValidator: async (data) =>
241
241
+
await zPlaceOrderResponse.parseAsync(data),
195
242
url: '/store/order',
196
243
});
197
244
···
216
263
) =>
217
264
(options?.client ?? client).get<TComposable, GetOrderByIdResponse, unknown>({
218
265
...options,
266
266
+
responseTransformer: getOrderByIdResponseTransformer,
267
267
+
responseValidator: async (data) =>
268
268
+
await zGetOrderByIdResponse.parseAsync(data),
219
269
url: '/store/order/{orderId}',
220
270
});
221
271
···
232
282
'Content-Type': 'application/json',
233
283
...options?.headers,
234
284
},
285
285
+
responseTransformer: createUserResponseTransformer,
286
286
+
responseValidator: async (data) =>
287
287
+
await zCreateUserResponse.parseAsync(data),
235
288
url: '/user',
236
289
});
237
290
···
252
305
'Content-Type': 'application/json',
253
306
...options?.headers,
254
307
},
308
308
+
responseValidator: async (data) =>
309
309
+
await zCreateUsersWithListInputResponse.parseAsync(data),
255
310
url: '/user/createWithList',
256
311
});
257
312
···
263
318
) =>
264
319
(options?.client ?? client).get<TComposable, LoginUserResponse, unknown>({
265
320
...options,
321
321
+
responseValidator: async (data) =>
322
322
+
await zLoginUserResponse.parseAsync(data),
266
323
url: '/user/login',
267
324
});
268
325
···
297
354
) =>
298
355
(options?.client ?? client).get<TComposable, GetUserByNameResponse, unknown>({
299
356
...options,
357
357
+
responseTransformer: getUserByNameResponseTransformer,
358
358
+
responseValidator: async (data) =>
359
359
+
await zGetUserByNameResponse.parseAsync(data),
300
360
url: '/user/{username}',
301
361
});
302
362
+125
examples/openapi-ts-nuxt/client/transformers.gen.ts
···
1
1
+
// This file is auto-generated by @hey-api/openapi-ts
2
2
+
3
3
+
import type {
4
4
+
AddPetResponse,
5
5
+
CreateUserResponse,
6
6
+
FindPetsByStatusResponse,
7
7
+
FindPetsByTagsResponse,
8
8
+
GetOrderByIdResponse,
9
9
+
GetPetByIdResponse,
10
10
+
GetUserByNameResponse,
11
11
+
PlaceOrderResponse,
12
12
+
UpdatePetResponse,
13
13
+
} from './types.gen';
14
14
+
15
15
+
const categorySchemaResponseTransformer = (data: any) => {
16
16
+
if (data.id) {
17
17
+
data.id = BigInt(data.id.toString());
18
18
+
}
19
19
+
return data;
20
20
+
};
21
21
+
22
22
+
const tagSchemaResponseTransformer = (data: any) => {
23
23
+
if (data.id) {
24
24
+
data.id = BigInt(data.id.toString());
25
25
+
}
26
26
+
return data;
27
27
+
};
28
28
+
29
29
+
const petSchemaResponseTransformer = (data: any) => {
30
30
+
if (data.id) {
31
31
+
data.id = BigInt(data.id.toString());
32
32
+
}
33
33
+
if (data.category) {
34
34
+
data.category = categorySchemaResponseTransformer(data.category);
35
35
+
}
36
36
+
if (data.tags) {
37
37
+
data.tags = data.tags.map((item: any) =>
38
38
+
tagSchemaResponseTransformer(item),
39
39
+
);
40
40
+
}
41
41
+
return data;
42
42
+
};
43
43
+
44
44
+
export const addPetResponseTransformer = async (
45
45
+
data: any,
46
46
+
): Promise<AddPetResponse> => {
47
47
+
data = petSchemaResponseTransformer(data);
48
48
+
return data;
49
49
+
};
50
50
+
51
51
+
export const updatePetResponseTransformer = async (
52
52
+
data: any,
53
53
+
): Promise<UpdatePetResponse> => {
54
54
+
data = petSchemaResponseTransformer(data);
55
55
+
return data;
56
56
+
};
57
57
+
58
58
+
export const findPetsByStatusResponseTransformer = async (
59
59
+
data: any,
60
60
+
): Promise<FindPetsByStatusResponse> => {
61
61
+
data = data.map((item: any) => petSchemaResponseTransformer(item));
62
62
+
return data;
63
63
+
};
64
64
+
65
65
+
export const findPetsByTagsResponseTransformer = async (
66
66
+
data: any,
67
67
+
): Promise<FindPetsByTagsResponse> => {
68
68
+
data = data.map((item: any) => petSchemaResponseTransformer(item));
69
69
+
return data;
70
70
+
};
71
71
+
72
72
+
export const getPetByIdResponseTransformer = async (
73
73
+
data: any,
74
74
+
): Promise<GetPetByIdResponse> => {
75
75
+
data = petSchemaResponseTransformer(data);
76
76
+
return data;
77
77
+
};
78
78
+
79
79
+
const orderSchemaResponseTransformer = (data: any) => {
80
80
+
if (data.id) {
81
81
+
data.id = BigInt(data.id.toString());
82
82
+
}
83
83
+
if (data.petId) {
84
84
+
data.petId = BigInt(data.petId.toString());
85
85
+
}
86
86
+
if (data.shipDate) {
87
87
+
data.shipDate = new Date(data.shipDate);
88
88
+
}
89
89
+
return data;
90
90
+
};
91
91
+
92
92
+
export const placeOrderResponseTransformer = async (
93
93
+
data: any,
94
94
+
): Promise<PlaceOrderResponse> => {
95
95
+
data = orderSchemaResponseTransformer(data);
96
96
+
return data;
97
97
+
};
98
98
+
99
99
+
export const getOrderByIdResponseTransformer = async (
100
100
+
data: any,
101
101
+
): Promise<GetOrderByIdResponse> => {
102
102
+
data = orderSchemaResponseTransformer(data);
103
103
+
return data;
104
104
+
};
105
105
+
106
106
+
const userSchemaResponseTransformer = (data: any) => {
107
107
+
if (data.id) {
108
108
+
data.id = BigInt(data.id.toString());
109
109
+
}
110
110
+
return data;
111
111
+
};
112
112
+
113
113
+
export const createUserResponseTransformer = async (
114
114
+
data: any,
115
115
+
): Promise<CreateUserResponse> => {
116
116
+
data = userSchemaResponseTransformer(data);
117
117
+
return data;
118
118
+
};
119
119
+
120
120
+
export const getUserByNameResponseTransformer = async (
121
121
+
data: any,
122
122
+
): Promise<GetUserByNameResponse> => {
123
123
+
data = userSchemaResponseTransformer(data);
124
124
+
return data;
125
125
+
};
+14
-14
examples/openapi-ts-nuxt/client/types.gen.ts
···
2
2
3
3
export type Order = {
4
4
complete?: boolean;
5
5
-
id?: number;
6
6
-
petId?: number;
5
5
+
id?: bigint;
6
6
+
petId?: bigint;
7
7
quantity?: number;
8
8
-
shipDate?: string;
8
8
+
shipDate?: Date;
9
9
/**
10
10
* Order Status
11
11
*/
···
14
14
15
15
export type Customer = {
16
16
address?: Array<Address>;
17
17
-
id?: number;
17
17
+
id?: bigint;
18
18
username?: string;
19
19
};
20
20
···
26
26
};
27
27
28
28
export type Category = {
29
29
-
id?: number;
29
29
+
id?: bigint;
30
30
name?: string;
31
31
};
32
32
33
33
export type User = {
34
34
email?: string;
35
35
firstName?: string;
36
36
-
id?: number;
36
36
+
id?: bigint;
37
37
lastName?: string;
38
38
password?: string;
39
39
phone?: string;
···
45
45
};
46
46
47
47
export type Tag = {
48
48
-
id?: number;
48
48
+
id?: bigint;
49
49
name?: string;
50
50
};
51
51
52
52
export type Pet = {
53
53
category?: Category;
54
54
-
id?: number;
54
54
+
id?: bigint;
55
55
name: string;
56
56
photoUrls: Array<string>;
57
57
/**
···
201
201
/**
202
202
* Pet id to delete
203
203
*/
204
204
-
petId: number;
204
204
+
petId: bigint;
205
205
};
206
206
query?: never;
207
207
url: '/pet/{petId}';
···
220
220
/**
221
221
* ID of pet to return
222
222
*/
223
223
-
petId: number;
223
223
+
petId: bigint;
224
224
};
225
225
query?: never;
226
226
url: '/pet/{petId}';
···
252
252
/**
253
253
* ID of pet that needs to be updated
254
254
*/
255
255
-
petId: number;
255
255
+
petId: bigint;
256
256
};
257
257
query?: {
258
258
/**
···
280
280
/**
281
281
* ID of pet to update
282
282
*/
283
283
-
petId: number;
283
283
+
petId: bigint;
284
284
};
285
285
query?: {
286
286
/**
···
348
348
/**
349
349
* ID of the order that needs to be deleted
350
350
*/
351
351
-
orderId: number;
351
351
+
orderId: bigint;
352
352
};
353
353
query?: never;
354
354
url: '/store/order/{orderId}';
···
371
371
/**
372
372
* ID of order that needs to be fetched
373
373
*/
374
374
-
orderId: number;
374
374
+
orderId: bigint;
375
375
};
376
376
query?: never;
377
377
url: '/store/order/{orderId}';
+96
examples/openapi-ts-nuxt/client/zod.gen.ts
···
1
1
+
// This file is auto-generated by @hey-api/openapi-ts
2
2
+
3
3
+
import { z } from 'zod';
4
4
+
5
5
+
export const zOrder = z.object({
6
6
+
complete: z.boolean().optional(),
7
7
+
id: z.coerce.bigint().optional(),
8
8
+
petId: z.coerce.bigint().optional(),
9
9
+
quantity: z.number().int().optional(),
10
10
+
shipDate: z.string().datetime().optional(),
11
11
+
status: z.enum(['placed', 'approved', 'delivered']).optional(),
12
12
+
});
13
13
+
14
14
+
export const zCustomer = z.object({
15
15
+
address: z
16
16
+
.array(
17
17
+
z.object({
18
18
+
city: z.string().optional(),
19
19
+
state: z.string().optional(),
20
20
+
street: z.string().optional(),
21
21
+
zip: z.string().optional(),
22
22
+
}),
23
23
+
)
24
24
+
.optional(),
25
25
+
id: z.coerce.bigint().optional(),
26
26
+
username: z.string().optional(),
27
27
+
});
28
28
+
29
29
+
export const zAddress = z.object({
30
30
+
city: z.string().optional(),
31
31
+
state: z.string().optional(),
32
32
+
street: z.string().optional(),
33
33
+
zip: z.string().optional(),
34
34
+
});
35
35
+
36
36
+
export const zCategory = z.object({
37
37
+
id: z.coerce.bigint().optional(),
38
38
+
name: z.string().optional(),
39
39
+
});
40
40
+
41
41
+
export const zUser = z.object({
42
42
+
email: z.string().optional(),
43
43
+
firstName: z.string().optional(),
44
44
+
id: z.coerce.bigint().optional(),
45
45
+
lastName: z.string().optional(),
46
46
+
password: z.string().optional(),
47
47
+
phone: z.string().optional(),
48
48
+
userStatus: z.number().int().optional(),
49
49
+
username: z.string().optional(),
50
50
+
});
51
51
+
52
52
+
export const zTag = z.object({
53
53
+
id: z.coerce.bigint().optional(),
54
54
+
name: z.string().optional(),
55
55
+
});
56
56
+
57
57
+
export const zPet = z.object({
58
58
+
category: zCategory.optional(),
59
59
+
id: z.coerce.bigint().optional(),
60
60
+
name: z.string(),
61
61
+
photoUrls: z.array(z.string()),
62
62
+
status: z.enum(['available', 'pending', 'sold']).optional(),
63
63
+
tags: z.array(zTag).optional(),
64
64
+
});
65
65
+
66
66
+
export const zApiResponse = z.object({
67
67
+
code: z.number().int().optional(),
68
68
+
message: z.string().optional(),
69
69
+
type: z.string().optional(),
70
70
+
});
71
71
+
72
72
+
export const zAddPetResponse = zPet;
73
73
+
74
74
+
export const zUpdatePetResponse = zPet;
75
75
+
76
76
+
export const zFindPetsByStatusResponse = z.array(zPet);
77
77
+
78
78
+
export const zFindPetsByTagsResponse = z.array(zPet);
79
79
+
80
80
+
export const zGetPetByIdResponse = zPet;
81
81
+
82
82
+
export const zUploadFileResponse = zApiResponse;
83
83
+
84
84
+
export const zGetInventoryResponse = z.object({});
85
85
+
86
86
+
export const zPlaceOrderResponse = zOrder;
87
87
+
88
88
+
export const zGetOrderByIdResponse = zOrder;
89
89
+
90
90
+
export const zCreateUserResponse = zUser;
91
91
+
92
92
+
export const zCreateUsersWithListInputResponse = z.union([zUser, z.unknown()]);
93
93
+
94
94
+
export const zLoginUserResponse = z.string();
95
95
+
96
96
+
export const zGetUserByNameResponse = zUser;
+6
-6
examples/openapi-ts-nuxt/components/home.vue
···
15
15
composable: 'useAsyncData',
16
16
key: 'item',
17
17
path: {
18
18
-
petId: 8,
18
18
+
petId: BigInt(8),
19
19
},
20
20
});
21
21
···
30
30
$fetch: requestFetch,
31
31
composable: 'useAsyncData',
32
32
path: {
33
33
-
petId: 8,
33
33
+
petId: BigInt(8),
34
34
},
35
35
});
36
36
···
42
42
const fetch = await getPetById({
43
43
composable: 'useFetch',
44
44
path: {
45
45
-
petId: 8,
45
45
+
petId: BigInt(8),
46
46
},
47
47
});
48
48
···
56
56
composable: 'useLazyAsyncData',
57
57
key: 'count',
58
58
path: {
59
59
-
petId: 8,
59
59
+
petId: BigInt(8),
60
60
},
61
61
});
62
62
watch(lazyAsyncData.data, (newPet) => {
···
76
76
const lazyFetch = await getPetById({
77
77
composable: 'useLazyFetch',
78
78
path: {
79
79
-
petId: 8,
79
79
+
petId: BigInt(8),
80
80
},
81
81
});
82
82
watch(lazyFetch.data, (newPet) => {
···
91
91
const result = await getPetById({
92
92
composable: '$fetch',
93
93
path: {
94
94
-
petId: 8,
94
94
+
petId: BigInt(8),
95
95
},
96
96
});
97
97
console.log(result);
+7
-1
examples/openapi-ts-nuxt/openapi-ts.config.ts
···
12
12
},
13
13
plugins: [
14
14
'@hey-api/schemas',
15
15
-
'@hey-api/sdk',
15
15
+
{
16
16
+
name: '@hey-api/sdk',
17
17
+
transformer: true,
18
18
+
validator: true,
19
19
+
},
16
20
{
17
21
enums: 'javascript',
18
22
name: '@hey-api/typescript',
19
23
},
24
24
+
'@hey-api/transformers',
25
25
+
'zod',
20
26
],
21
27
});
+2
-1
examples/openapi-ts-nuxt/package.json
···
16
16
"@hey-api/client-nuxt": "workspace:*",
17
17
"nuxt": "3.15.1",
18
18
"vue": "3.5.13",
19
19
-
"vue-router": "4.5.0"
19
19
+
"vue-router": "4.5.0",
20
20
+
"zod": "3.23.8"
20
21
},
21
22
"devDependencies": {
22
23
"@hey-api/openapi-ts": "workspace:*"
+72
-134
packages/client-nuxt/src/__tests__/utils.test.ts
···
1
1
import { describe, expect, it, vi } from 'vitest';
2
2
3
3
-
import { getAuthToken, getParseAs, setAuthParams } from '../utils';
3
3
+
import type { Auth } from '../types';
4
4
+
import { getAuthToken, setAuthParams } from '../utils';
4
5
5
6
describe('getAuthToken', () => {
6
6
-
it('returns access token', async () => {
7
7
-
const accessToken = vi.fn().mockReturnValue('foo');
8
8
-
const apiKey = vi.fn().mockReturnValue('bar');
7
7
+
it('returns bearer token', async () => {
8
8
+
const auth = vi.fn().mockReturnValue('foo');
9
9
const token = await getAuthToken(
10
10
{
11
11
-
fn: 'accessToken',
12
12
-
in: 'header',
13
13
-
name: 'baz',
14
14
-
},
15
15
-
{
16
16
-
accessToken,
17
17
-
apiKey,
11
11
+
scheme: 'bearer',
12
12
+
type: 'http',
18
13
},
14
14
+
auth,
19
15
);
20
20
-
expect(accessToken).toHaveBeenCalled();
16
16
+
expect(auth).toHaveBeenCalled();
21
17
expect(token).toBe('Bearer foo');
22
18
});
23
19
24
24
-
it('returns nothing when accessToken function is undefined', async () => {
25
25
-
const apiKey = vi.fn().mockReturnValue('bar');
20
20
+
it('returns basic token', async () => {
21
21
+
const auth = vi.fn().mockReturnValue('foo:bar');
26
22
const token = await getAuthToken(
27
23
{
28
28
-
fn: 'accessToken',
29
29
-
in: 'header',
30
30
-
name: 'baz',
24
24
+
scheme: 'basic',
25
25
+
type: 'http',
31
26
},
32
32
-
{
33
33
-
apiKey,
34
34
-
},
27
27
+
auth,
35
28
);
36
36
-
expect(token).toBeUndefined();
29
29
+
expect(auth).toHaveBeenCalled();
30
30
+
expect(token).toBe(`Basic ${btoa('foo:bar')}`);
37
31
});
38
32
39
39
-
it('returns API key', async () => {
40
40
-
const accessToken = vi.fn().mockReturnValue('foo');
41
41
-
const apiKey = vi.fn().mockReturnValue('bar');
33
33
+
it('returns raw token', async () => {
34
34
+
const auth = vi.fn().mockReturnValue('foo');
42
35
const token = await getAuthToken(
43
36
{
44
44
-
fn: 'apiKey',
45
45
-
in: 'header',
46
46
-
name: 'baz',
37
37
+
type: 'http',
47
38
},
48
48
-
{
49
49
-
accessToken,
50
50
-
apiKey,
51
51
-
},
39
39
+
auth,
52
40
);
53
53
-
expect(apiKey).toHaveBeenCalled();
54
54
-
expect(token).toBe('bar');
41
41
+
expect(auth).toHaveBeenCalled();
42
42
+
expect(token).toBe('foo');
55
43
});
56
44
57
57
-
it('returns nothing when apiKey function is undefined', async () => {
58
58
-
const accessToken = vi.fn().mockReturnValue('foo');
45
45
+
it('returns nothing when auth function is undefined', async () => {
59
46
const token = await getAuthToken(
60
47
{
61
61
-
fn: 'apiKey',
62
62
-
in: 'header',
63
63
-
name: 'baz',
48
48
+
type: 'http',
64
49
},
65
65
-
{
66
66
-
accessToken,
67
67
-
},
50
50
+
undefined,
68
51
);
69
52
expect(token).toBeUndefined();
70
53
});
71
54
});
72
55
73
73
-
describe('getParseAs', () => {
74
74
-
const scenarios: Array<{
75
75
-
content: Parameters<typeof getParseAs>[0];
76
76
-
parseAs: ReturnType<typeof getParseAs>;
77
77
-
}> = [
78
78
-
{
79
79
-
content: null,
80
80
-
parseAs: 'stream',
81
81
-
},
82
82
-
{
83
83
-
content: 'application/json',
84
84
-
parseAs: 'json',
85
85
-
},
86
86
-
{
87
87
-
content: 'application/ld+json',
88
88
-
parseAs: 'json',
89
89
-
},
90
90
-
{
91
91
-
content: 'application/ld+json;charset=utf-8',
92
92
-
parseAs: 'json',
93
93
-
},
94
94
-
{
95
95
-
content: 'application/ld+json; charset=utf-8',
96
96
-
parseAs: 'json',
97
97
-
},
98
98
-
{
99
99
-
content: 'multipart/form-data',
100
100
-
parseAs: 'formData',
101
101
-
},
102
102
-
{
103
103
-
content: 'application/*',
104
104
-
parseAs: 'blob',
105
105
-
},
106
106
-
{
107
107
-
content: 'audio/*',
108
108
-
parseAs: 'blob',
109
109
-
},
110
110
-
{
111
111
-
content: 'image/*',
112
112
-
parseAs: 'blob',
113
113
-
},
114
114
-
{
115
115
-
content: 'video/*',
116
116
-
parseAs: 'blob',
117
117
-
},
118
118
-
{
119
119
-
content: 'text/*',
120
120
-
parseAs: 'text',
121
121
-
},
122
122
-
{
123
123
-
content: 'unsupported',
124
124
-
parseAs: undefined,
125
125
-
},
126
126
-
];
127
127
-
128
128
-
it.each(scenarios)(
129
129
-
'detects $content as $parseAs',
130
130
-
async ({ content, parseAs }) => {
131
131
-
expect(getParseAs(content)).toEqual(parseAs);
132
132
-
},
133
133
-
);
134
134
-
});
135
135
-
136
56
describe('setAuthParams', () => {
137
137
-
it('sets access token in headers', async () => {
138
138
-
const accessToken = vi.fn().mockReturnValue('foo');
139
139
-
const apiKey = vi.fn().mockReturnValue('bar');
57
57
+
it('sets bearer token in headers', async () => {
58
58
+
const auth = vi.fn().mockReturnValue('foo');
140
59
const headers = new Headers();
141
60
const query: Record<any, unknown> = {};
142
61
await setAuthParams({
143
143
-
accessToken,
144
144
-
apiKey,
62
62
+
auth,
145
63
headers,
146
64
query,
147
65
security: [
148
66
{
149
149
-
fn: 'accessToken',
150
150
-
in: 'header',
151
67
name: 'baz',
68
68
+
scheme: 'bearer',
69
69
+
type: 'http',
152
70
},
153
71
],
154
72
});
155
155
-
expect(accessToken).toHaveBeenCalled();
73
73
+
expect(auth).toHaveBeenCalled();
156
74
expect(headers.get('baz')).toBe('Bearer foo');
157
75
expect(Object.keys(query).length).toBe(0);
158
76
});
159
77
160
78
it('sets access token in query', async () => {
161
161
-
const accessToken = vi.fn().mockReturnValue('foo');
162
162
-
const apiKey = vi.fn().mockReturnValue('bar');
79
79
+
const auth = vi.fn().mockReturnValue('foo');
163
80
const headers = new Headers();
164
81
const query: Record<any, unknown> = {};
165
82
await setAuthParams({
166
166
-
accessToken,
167
167
-
apiKey,
83
83
+
auth,
168
84
headers,
169
85
query,
170
86
security: [
171
87
{
172
172
-
fn: 'accessToken',
173
88
in: 'query',
174
89
name: 'baz',
90
90
+
scheme: 'bearer',
91
91
+
type: 'http',
175
92
},
176
93
],
177
94
});
178
178
-
expect(accessToken).toHaveBeenCalled();
95
95
+
expect(auth).toHaveBeenCalled();
179
96
expect(headers.get('baz')).toBeNull();
180
97
expect(query.baz).toBe('Bearer foo');
181
98
});
182
99
100
100
+
it('sets Authorization header when `in` and `name` are undefined', async () => {
101
101
+
const auth = vi.fn().mockReturnValue('foo');
102
102
+
const headers = new Headers();
103
103
+
const query: Record<any, unknown> = {};
104
104
+
await setAuthParams({
105
105
+
auth,
106
106
+
headers,
107
107
+
query,
108
108
+
security: [
109
109
+
{
110
110
+
type: 'http',
111
111
+
},
112
112
+
],
113
113
+
});
114
114
+
expect(auth).toHaveBeenCalled();
115
115
+
expect(headers.get('Authorization')).toBe('foo');
116
116
+
expect(query).toEqual({});
117
117
+
});
118
118
+
183
119
it('sets first scheme only', async () => {
184
184
-
const accessToken = vi.fn().mockReturnValue('foo');
185
185
-
const apiKey = vi.fn().mockReturnValue('bar');
120
120
+
const auth = vi.fn().mockReturnValue('foo');
186
121
const headers = new Headers();
187
122
const query: Record<any, unknown> = {};
188
123
await setAuthParams({
189
189
-
accessToken,
190
190
-
apiKey,
124
124
+
auth,
191
125
headers,
192
126
query,
193
127
security: [
194
128
{
195
195
-
fn: 'accessToken',
196
196
-
in: 'header',
197
129
name: 'baz',
130
130
+
scheme: 'bearer',
131
131
+
type: 'http',
198
132
},
199
133
{
200
200
-
fn: 'accessToken',
201
134
in: 'query',
202
135
name: 'baz',
136
136
+
scheme: 'bearer',
137
137
+
type: 'http',
203
138
},
204
139
],
205
140
});
206
206
-
expect(accessToken).toHaveBeenCalled();
141
141
+
expect(auth).toHaveBeenCalled();
207
142
expect(headers.get('baz')).toBe('Bearer foo');
208
143
expect(Object.keys(query).length).toBe(0);
209
144
});
210
145
211
146
it('sets first scheme with token', async () => {
212
212
-
const accessToken = vi.fn().mockReturnValue('foo');
213
213
-
const apiKey = vi.fn().mockReturnValue(undefined);
147
147
+
const auth = vi.fn().mockImplementation((auth: Auth) => {
148
148
+
if (auth.type === 'apiKey') {
149
149
+
return;
150
150
+
}
151
151
+
return 'foo';
152
152
+
});
214
153
const headers = new Headers();
215
154
const query: Record<any, unknown> = {};
216
155
await setAuthParams({
217
217
-
accessToken,
218
218
-
apiKey,
156
156
+
auth,
219
157
headers,
220
158
query,
221
159
security: [
222
160
{
223
223
-
fn: 'apiKey',
224
224
-
in: 'header',
225
161
name: 'baz',
162
162
+
type: 'apiKey',
226
163
},
227
164
{
228
228
-
fn: 'accessToken',
229
165
in: 'query',
230
166
name: 'baz',
167
167
+
scheme: 'bearer',
168
168
+
type: 'http',
231
169
},
232
170
],
233
171
});
234
234
-
expect(accessToken).toHaveBeenCalled();
172
172
+
expect(auth).toHaveBeenCalled();
235
173
expect(headers.get('baz')).toBeNull();
236
174
expect(query.baz).toBe('Bearer foo');
237
175
});
+17
-11
packages/client-nuxt/src/index.ts
···
38
38
headers: mergeHeaders(_config.headers, options.headers),
39
39
};
40
40
41
41
-
const { security } = opts;
41
41
+
const { responseTransformer, responseValidator, security } = opts;
42
42
if (security) {
43
43
// auth must happen in interceptors otherwise we'd need to require
44
44
// asyncContext enabled
···
53
53
};
54
54
}
55
55
56
56
+
if (responseTransformer || responseValidator) {
57
57
+
opts.onResponse = async ({ options, response }) => {
58
58
+
if (options.responseType && options.responseType !== 'json') {
59
59
+
return;
60
60
+
}
61
61
+
62
62
+
if (responseValidator) {
63
63
+
await responseValidator(response._data);
64
64
+
}
65
65
+
66
66
+
if (responseTransformer) {
67
67
+
response._data = await responseTransformer(response._data);
68
68
+
}
69
69
+
};
70
70
+
}
71
71
+
56
72
if (opts.body && opts.bodySerializer) {
57
73
opts.body = opts.bodySerializer(opts.body);
58
74
}
···
65
81
const url = buildUrl(opts);
66
82
67
83
const fetchFn = opts.$fetch;
68
68
-
69
69
-
// if (parseAs === 'json') {
70
70
-
// if (opts.responseValidator) {
71
71
-
// await opts.responseValidator(data);
72
72
-
// }
73
73
-
74
74
-
// if (opts.responseTransformer) {
75
75
-
// data = await opts.responseTransformer(data);
76
76
-
// }
77
77
-
// }
78
84
79
85
if (composable === '$fetch') {
80
86
// @ts-expect-error
+2
packages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts
···
491
491
types: isNuxtClient
492
492
? [
493
493
{
494
494
+
// default: compiler.ots.string('$fetch'),
494
495
extends: compiler.typeNode('Composable'),
495
496
name: nuxtTypeComposable,
496
497
},
···
572
573
types: isNuxtClient
573
574
? [
574
575
{
576
576
+
// default: compiler.ots.string('$fetch'),
575
577
extends: compiler.typeNode('Composable'),
576
578
name: nuxtTypeComposable,
577
579
},
+13
-6
packages/openapi-ts/src/plugins/zod/plugin.ts
···
22
22
export const zodId = 'zod';
23
23
24
24
// frequently used identifiers
25
25
+
const coerceIdentifier = compiler.identifier({ text: 'coerce' });
25
26
const defaultIdentifier = compiler.identifier({ text: 'default' });
26
27
const intersectionIdentifier = compiler.identifier({ text: 'intersection' });
27
28
const lazyIdentifier = compiler.identifier({ text: 'lazy' });
···
263
264
}
264
265
265
266
let numberExpression = compiler.callExpression({
266
266
-
functionName: compiler.propertyAccessExpression({
267
267
-
expression: zIdentifier,
268
268
-
name: isBigInt
269
269
-
? compiler.identifier({ text: 'bigint' })
270
270
-
: compiler.identifier({ text: 'number' }),
271
271
-
}),
267
267
+
functionName: isBigInt
268
268
+
? compiler.propertyAccessExpression({
269
269
+
expression: compiler.propertyAccessExpression({
270
270
+
expression: zIdentifier,
271
271
+
name: coerceIdentifier,
272
272
+
}),
273
273
+
name: compiler.identifier({ text: 'bigint' }),
274
274
+
})
275
275
+
: compiler.propertyAccessExpression({
276
276
+
expression: zIdentifier,
277
277
+
name: compiler.identifier({ text: 'number' }),
278
278
+
}),
272
279
});
273
280
274
281
if (!isBigInt && schema.type === 'integer') {
+3
pnpm-lock.yaml
···
264
264
vue-router:
265
265
specifier: 4.5.0
266
266
version: 4.5.0(vue@3.5.13(typescript@5.6.1-rc))
267
267
+
zod:
268
268
+
specifier: 3.23.8
269
269
+
version: 3.23.8
267
270
devDependencies:
268
271
'@hey-api/openapi-ts':
269
272
specifier: workspace:*