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: update types to support refs
Lubos
1 year ago
7e4b6d84
be2a6e16
+92
-59
7 changed files
expand all
collapse all
unified
split
examples
openapi-ts-nuxt
.npmrc
components
home.vue
packages
client-nuxt
package.json
src
index.ts
types.ts
utils.ts
pnpm-lock.yaml
+2
examples/openapi-ts-nuxt/.npmrc
···
1
1
+
engine-strict=true
2
2
+
save-exact=true
+2
-1
examples/openapi-ts-nuxt/components/home.vue
···
88
88
});
89
89
90
90
async function handleFetch() {
91
91
+
const petId = ref(BigInt(8));
91
92
const result = await getPetById({
92
93
composable: '$fetch',
93
94
path: {
94
94
-
petId: BigInt(8),
95
95
+
petId,
95
96
},
96
97
});
97
98
console.log(result);
+3
-3
packages/client-nuxt/package.json
···
66
66
"typecheck": "vitest --typecheck --watch=false"
67
67
},
68
68
"peerDependencies": {
69
69
-
"nuxt": ">= 3.0.0 < 4"
69
69
+
"nuxt": ">= 3.0.0 < 4",
70
70
+
"vue": ">= 3.5.13 < 4"
70
71
},
71
72
"devDependencies": {
72
72
-
"@nuxt/test-utils": "3.15.1",
73
73
-
"nuxt": "3.15.1"
73
73
+
"@nuxt/test-utils": "3.15.1"
74
74
}
75
75
}
+21
-9
packages/client-nuxt/src/index.ts
···
40
40
41
41
const { responseTransformer, responseValidator, security } = opts;
42
42
if (security) {
43
43
+
const _onRequest = opts.onRequest;
43
44
// auth must happen in interceptors otherwise we'd need to require
44
45
// asyncContext enabled
45
46
// https://nuxt.com/docs/guide/going-further/experimental-features#asynccontext
46
46
-
opts.onRequest = async ({ options }) => {
47
47
+
opts.onRequest = async (context) => {
48
48
+
const { options } = context;
49
49
+
47
50
await setAuthParams({
48
51
auth: opts.auth,
49
52
headers: options.headers,
50
53
query: options.query,
51
54
security,
52
55
});
56
56
+
57
57
+
if (typeof _onRequest === 'function') {
58
58
+
await _onRequest(context);
59
59
+
}
53
60
};
54
61
}
55
62
56
63
if (responseTransformer || responseValidator) {
57
57
-
opts.onResponse = async ({ options, response }) => {
58
58
-
if (options.responseType && options.responseType !== 'json') {
59
59
-
return;
60
60
-
}
64
64
+
const _onResponse = opts.onResponse;
65
65
+
opts.onResponse = async (context) => {
66
66
+
const { options, response } = context;
61
67
62
62
-
if (responseValidator) {
63
63
-
await responseValidator(response._data);
68
68
+
if (!options.responseType || options.responseType === 'json') {
69
69
+
if (responseValidator) {
70
70
+
await responseValidator(response._data);
71
71
+
}
72
72
+
73
73
+
if (responseTransformer) {
74
74
+
response._data = await responseTransformer(response._data);
75
75
+
}
64
76
}
65
77
66
66
-
if (responseTransformer) {
67
67
-
response._data = await responseTransformer(response._data);
78
78
+
if (typeof _onResponse === 'function') {
79
79
+
await _onResponse(context);
68
80
}
69
81
};
70
82
}
+39
-31
packages/client-nuxt/src/types.ts
···
6
6
useLazyAsyncData,
7
7
useLazyFetch,
8
8
} from 'nuxt/app';
9
9
+
import type { Ref } from 'vue';
9
10
10
11
import type {
11
12
BodySerializer,
···
14
15
} from './utils';
15
16
16
17
type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>;
18
18
+
19
19
+
type WithRefs<TData> = {
20
20
+
[K in keyof TData]: TData[K] extends object
21
21
+
? WithRefs<TData[K]> | Ref<TData[K]>
22
22
+
: TData[K] | Ref<TData[K]>;
23
23
+
};
17
24
18
25
export interface Config
19
26
extends Omit<
20
20
-
FetchOptions<unknown>,
21
21
-
'baseURL' | 'body' | 'headers' | 'method'
22
22
-
> {
27
27
+
FetchOptions<unknown>,
28
28
+
'baseURL' | 'body' | 'headers' | 'method' | 'query'
29
29
+
>,
30
30
+
WithRefs<Pick<FetchOptions<unknown>, 'query'>> {
23
31
/**
24
32
* **This feature works only with the [experimental parser](https://heyapi.dev/openapi-ts/configuration#parser)**
25
33
*
···
106
114
export interface RequestOptions<
107
115
TComposable extends Composable = Composable,
108
116
Url extends string = string,
109
109
-
> extends Config {
117
117
+
> extends Config,
118
118
+
WithRefs<{
119
119
+
/**
120
120
+
* Any body that you want to add to your request.
121
121
+
*
122
122
+
* {@link https://developer.mozilla.org/docs/Web/API/fetch#body}
123
123
+
*/
124
124
+
body?: BodyInit | Record<string, any> | null;
125
125
+
path?: Record<string, unknown>;
126
126
+
query?: FetchOptions<unknown>['query'];
127
127
+
}> {
110
128
asyncDataOptions?: AsyncDataOptions<unknown>;
111
129
/**
112
112
-
* Any body that you want to add to your request.
113
113
-
*
114
114
-
* {@link https://developer.mozilla.org/docs/Web/API/fetch#body}
115
115
-
*/
116
116
-
body?: BodyInit | Record<string, any> | null;
117
117
-
/**
118
130
* You can provide a client instance returned by `createClient()` instead of
119
131
* individual options. This might be also useful if you want to implement a
120
132
* custom client.
···
122
134
client?: Client;
123
135
composable: TComposable;
124
136
key?: string;
125
125
-
path?: Record<string, unknown>;
126
126
-
query?: FetchOptions<unknown>['query'];
127
137
/**
128
138
* Security mechanism(s) to use for the request.
129
139
*/
···
164
174
Pick<Required<RequestOptions<TComposable>>, 'method'>,
165
175
) => RequestResult<TComposable, TData, TError>;
166
176
177
177
+
interface DataShape {
178
178
+
body?: unknown;
179
179
+
headers?: unknown;
180
180
+
path?: Record<string, unknown>;
181
181
+
query?: unknown;
182
182
+
url: string;
183
183
+
}
184
184
+
185
185
+
export type BuildUrlOptions<
186
186
+
TData extends Omit<DataShape, 'headers'> = Omit<DataShape, 'headers'>,
187
187
+
> = Pick<WithRefs<TData>, 'path' | 'query'> &
188
188
+
Pick<TData, 'url'> &
189
189
+
Pick<Options<'$fetch', TData>, 'baseURL' | 'querySerializer'>;
190
190
+
167
191
export interface Client {
168
192
/**
169
193
* Returns the final request URL. This method works only with experimental parser.
170
194
*/
171
171
-
buildUrl: <
172
172
-
TData extends {
173
173
-
body?: unknown;
174
174
-
path?: Record<string, unknown>;
175
175
-
query?: FetchOptions<unknown>['query'];
176
176
-
url: string;
177
177
-
},
178
178
-
>(
179
179
-
options: Pick<TData, 'path' | 'query' | 'url'> &
180
180
-
Pick<Options<'$fetch', TData>, 'baseURL' | 'querySerializer'>,
195
195
+
buildUrl: <TData extends Omit<DataShape, 'headers'>>(
196
196
+
options: BuildUrlOptions<TData>,
181
197
) => string;
182
198
connect: MethodFn;
183
199
delete: MethodFn;
···
193
209
trace: MethodFn;
194
210
}
195
211
196
196
-
interface DataShape {
197
197
-
body?: unknown;
198
198
-
headers?: unknown;
199
199
-
path?: unknown;
200
200
-
query?: unknown;
201
201
-
url: string;
202
202
-
}
203
203
-
204
212
export type Options<
205
213
TComposable extends Composable,
206
214
TData extends DataShape = DataShape,
207
215
> = OmitKeys<RequestOptions<TComposable>, 'body' | 'path' | 'query' | 'url'> &
208
208
-
Omit<TData, 'url'>;
216
216
+
WithRefs<Omit<TData, 'url'>>;
209
217
210
218
export type OptionsLegacyParser<TData = unknown> = TData extends { body?: any }
211
219
? TData extends { headers?: any }
+18
-12
packages/client-nuxt/src/utils.ts
···
1
1
-
import type { Auth, Client, Config, RequestOptions } from './types';
1
1
+
import { toValue } from 'vue';
2
2
+
3
3
+
import type {
4
4
+
Auth,
5
5
+
BuildUrlOptions,
6
6
+
Client,
7
7
+
Config,
8
8
+
RequestOptions,
9
9
+
} from './types';
2
10
3
3
-
interface PathSerializer {
4
4
-
path: Record<string, unknown>;
5
5
-
url: string;
6
6
-
}
11
11
+
type PathSerializer = Pick<Required<BuildUrlOptions>, 'path' | 'url'>;
7
12
8
13
const PATH_PARAM_RE = /\{[^{}]+\}/g;
9
14
···
217
222
style = 'matrix';
218
223
}
219
224
220
220
-
const value = path[name];
225
225
+
// @ts-expect-error
226
226
+
const value = toValue(toValue(path)[name]);
221
227
222
228
if (value === undefined || value === null) {
223
229
continue;
···
271
277
}: QuerySerializerOptions = {}) => {
272
278
const querySerializer = (queryParams: T) => {
273
279
let search: string[] = [];
274
274
-
if (queryParams && typeof queryParams === 'object') {
275
275
-
for (const name in queryParams) {
276
276
-
const value = queryParams[name];
280
280
+
const qParams = toValue(queryParams);
281
281
+
if (qParams && typeof qParams === 'object') {
282
282
+
for (const name in qParams) {
283
283
+
const value = toValue(qParams[name]);
277
284
278
285
if (value === undefined || value === null) {
279
286
continue;
···
367
374
if (!options.query) {
368
375
options.query = {};
369
376
}
370
370
-
// TODO: handle refs
371
377
// @ts-expect-error
372
372
-
options.query[name] = token;
378
378
+
toValue(options.query)[name] = token;
373
379
break;
374
380
case 'header':
375
381
default:
···
401
407
query,
402
408
querySerializer,
403
409
url: _url,
404
404
-
}: Pick<Parameters<Client['buildUrl']>[0], 'path' | 'query' | 'url'> & {
410
410
+
}: Pick<BuildUrlOptions, 'path' | 'query' | 'url'> & {
405
411
baseUrl: string;
406
412
querySerializer: QuerySerializer;
407
413
}) => {
+7
-3
pnpm-lock.yaml
···
602
602
packages/client-fetch: {}
603
603
604
604
packages/client-nuxt:
605
605
+
dependencies:
606
606
+
nuxt:
607
607
+
specifier: '>= 3.0.0 < 4'
608
608
+
version: 3.15.1(@parcel/watcher@2.5.0)(@types/node@22.10.5)(db0@0.2.1)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.30.1)(sass@1.80.7)(terser@5.36.0)(typescript@5.6.1-rc)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)(yaml@2.7.0))(yaml@2.7.0)
609
609
+
vue:
610
610
+
specifier: '>= 3.5.13 < 4'
611
611
+
version: 3.5.13(typescript@5.6.1-rc)
605
612
devDependencies:
606
613
'@nuxt/test-utils':
607
614
specifier: 3.15.1
608
615
version: 3.15.1(@types/node@22.10.5)(@vue/test-utils@2.4.6)(jsdom@24.1.0)(less@4.2.0)(magicast@0.3.5)(rollup@4.30.1)(sass@1.80.7)(terser@5.36.0)(typescript@5.6.1-rc)(vitest@1.6.0(@types/node@22.10.5)(jsdom@24.1.0)(less@4.2.0)(sass@1.80.7)(terser@5.36.0))
609
609
-
nuxt:
610
610
-
specifier: 3.15.1
611
611
-
version: 3.15.1(@parcel/watcher@2.5.0)(@types/node@22.10.5)(db0@0.2.1)(encoding@0.1.13)(eslint@9.17.0(jiti@2.4.2))(ioredis@5.4.2)(less@4.2.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.30.1)(sass@1.80.7)(terser@5.36.0)(typescript@5.6.1-rc)(vite@6.0.7(@types/node@22.10.5)(jiti@2.4.2)(less@4.2.0)(sass@1.80.7)(terser@5.36.0)(yaml@2.7.0))(yaml@2.7.0)
612
616
613
617
packages/openapi-ts:
614
618
dependencies: