forked from openapi-ts/openapi-typescript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
125 lines (120 loc) · 5.09 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import {
type UseMutationOptions,
type UseMutationResult,
type UseQueryOptions,
type UseQueryResult,
type UseSuspenseQueryOptions,
type UseSuspenseQueryResult,
type QueryClient,
useMutation,
useQuery,
useSuspenseQuery,
} from "@tanstack/react-query";
import type { ClientMethod, FetchResponse, MaybeOptionalInit, Client as FetchClient } from "openapi-fetch";
import type { HttpMethod, MediaType, PathsWithMethod, RequiredKeysOf } from "openapi-typescript-helpers";
export type UseQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, Media extends MediaType> = <
Method extends HttpMethod,
Path extends PathsWithMethod<Paths, Method>,
Init extends MaybeOptionalInit<Paths[Path], Method>,
Response extends Required<FetchResponse<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types
Options extends Omit<UseQueryOptions<Response["data"], Response["error"]>, "queryKey" | "queryFn">,
>(
method: Method,
url: Path,
...[init, options, queryClient]: RequiredKeysOf<Init> extends never
? [(Init & { [key: string]: unknown })?, Options?, QueryClient?]
: [Init & { [key: string]: unknown }, Options?, QueryClient?]
) => UseQueryResult<Response["data"], Response["error"]>;
export type UseSuspenseQueryMethod<Paths extends Record<string, Record<HttpMethod, {}>>, Media extends MediaType> = <
Method extends HttpMethod,
Path extends PathsWithMethod<Paths, Method>,
Init extends MaybeOptionalInit<Paths[Path], Method>,
Response extends Required<FetchResponse<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types
Options extends Omit<UseSuspenseQueryOptions<Response["data"], Response["error"]>, "queryKey" | "queryFn">,
>(
method: Method,
url: Path,
...[init, options, queryClient]: RequiredKeysOf<Init> extends never
? [(Init & { [key: string]: unknown })?, Options?, QueryClient?]
: [Init & { [key: string]: unknown }, Options?, QueryClient?]
) => UseSuspenseQueryResult<Response["data"], Response["error"]>;
export type UseMutationMethod<Paths extends Record<string, Record<HttpMethod, {}>>, Media extends MediaType> = <
Method extends HttpMethod,
Path extends PathsWithMethod<Paths, Method>,
Init extends MaybeOptionalInit<Paths[Path], Method>,
Response extends Required<FetchResponse<Paths[Path][Method], Init, Media>>, // note: Required is used to avoid repeating NonNullable in UseQuery types
Options extends Omit<UseMutationOptions<Response["data"], Response["error"], Init>, "mutationKey" | "mutationFn">,
>(
method: Method,
url: Path,
options?: Options,
queryClient?: QueryClient,
) => UseMutationResult<Response["data"], Response["error"], Init>;
export interface OpenapiQueryClient<Paths extends {}, Media extends MediaType = MediaType> {
useQuery: UseQueryMethod<Paths, Media>;
useSuspenseQuery: UseSuspenseQueryMethod<Paths, Media>;
useMutation: UseMutationMethod<Paths, Media>;
}
// TODO: Move the client[method]() fn outside for reusability
// TODO: Add the ability to bring queryClient as argument
export default function createClient<Paths extends {}, Media extends MediaType = MediaType>(
client: FetchClient<Paths, Media>,
): OpenapiQueryClient<Paths, Media> {
return {
useQuery: (method, path, ...[init, options, queryClient]) => {
return useQuery(
{
queryKey: [method, path, init],
queryFn: async () => {
const mth = method.toUpperCase() as keyof typeof client;
const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;
const { data, error } = await fn(path, init as any); // TODO: find a way to avoid as any
if (error || !data) {
throw error;
}
return data;
},
...options,
},
queryClient,
);
},
useSuspenseQuery: (method, path, ...[init, options, queryClient]) => {
return useSuspenseQuery(
{
queryKey: [method, path, init],
queryFn: async () => {
const mth = method.toUpperCase() as keyof typeof client;
const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;
const { data, error } = await fn(path, init as any); // TODO: find a way to avoid as any
if (error || !data) {
throw error;
}
return data;
},
...options,
},
queryClient,
);
},
useMutation: (method, path, options, queryClient) => {
return useMutation(
{
mutationKey: [method, path],
mutationFn: async (init) => {
// TODO: Put in external fn for reusability
const mth = method.toUpperCase() as keyof typeof client;
const fn = client[mth] as ClientMethod<Paths, typeof method, Media>;
const { data, error } = await fn(path, init as any); // TODO: find a way to avoid as any
if (error || !data) {
throw error;
}
return data;
},
...options,
},
queryClient,
);
},
};
}