@ryneex/api-client 1.0.0-beta.1 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +40 -10
- package/index.js +120 -69
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as axios from 'axios';
|
|
2
|
-
import { AxiosRequestConfig, AxiosError, AxiosInstance } from 'axios';
|
|
2
|
+
import { AxiosRequestConfig, AxiosResponse, AxiosError, AxiosInstance } from 'axios';
|
|
3
3
|
import z, { ZodError } from 'zod';
|
|
4
4
|
import { UseQueryOptions, UseMutationOptions } from '@tanstack/react-query';
|
|
5
5
|
|
|
@@ -19,22 +19,32 @@ type ClientOptions<TOutputSchema extends z.ZodType, TInputSchema extends z.ZodTy
|
|
|
19
19
|
transform?: (data: z.infer<TOutputSchema>, payload: ClientPayload<TInput, TVariables>) => TOutput;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
type ReactQueryOptions<TOutput, TInput, TVariables> = Omit<UseQueryOptions<TOutput,
|
|
22
|
+
type ReactQueryOptions<TOutput, TInput, TVariables> = Omit<UseQueryOptions<TOutput, ClientError>, "queryFn" | "queryKey"> & {
|
|
23
23
|
queryKey?: unknown[];
|
|
24
24
|
} & (object extends ClientPayload<TInput, TVariables> ? unknown : {
|
|
25
25
|
data: ClientPayload<TInput, TVariables>;
|
|
26
26
|
}) & {
|
|
27
27
|
onSuccess?: (data: TOutput, payload: ClientPayload<TInput, TVariables>) => void;
|
|
28
|
-
onError?: (error:
|
|
28
|
+
onError?: (error: ClientError, payload: ClientPayload<TInput, TVariables>) => void;
|
|
29
29
|
};
|
|
30
|
-
type ReactMutationOptions<TOutput, TInput, TVariables> = Omit<UseMutationOptions<TOutput,
|
|
30
|
+
type ReactMutationOptions<TOutput, TInput, TVariables> = Omit<UseMutationOptions<TOutput, ClientError, object extends ClientPayload<TInput, TVariables> ? void : ClientPayload<TInput, TVariables>>, "mutationFn"> & {};
|
|
31
|
+
|
|
32
|
+
type Ok<T> = {
|
|
33
|
+
success: true;
|
|
34
|
+
data: T;
|
|
35
|
+
response: AxiosResponse;
|
|
36
|
+
};
|
|
37
|
+
type ClientError = ValidationError | AxiosError;
|
|
38
|
+
type Err<E> = {
|
|
39
|
+
success: false;
|
|
40
|
+
error: E;
|
|
41
|
+
};
|
|
42
|
+
type Result<T, E> = Ok<T> | Err<E>;
|
|
31
43
|
|
|
32
44
|
declare function createClient(axios: AxiosInstance): {
|
|
33
|
-
create: <TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.core.output<TOutputSchema>, TInput = z.core.output<TInputSchema>, TVariables = z.core.output<TVariablesSchema>>(opts: ClientOptions<TOutputSchema, TInputSchema, TVariablesSchema, TOutput, TInput, TVariables>) => ((_payload: OptionalPayload<ClientPayload<TInput, TVariables>>) => Promise<
|
|
34
|
-
queryOptions: (_opts: object extends ClientPayload<TInput, TVariables> ? ReactQueryOptions<TOutput, TInput, TVariables> | void : ReactQueryOptions<TOutput, TInput, TVariables>) => UseQueryOptions<TOutput,
|
|
35
|
-
mutationOptions: (_opts: ReactMutationOptions<TOutput, TInput, TVariables> | void) => UseMutationOptions<TOutput,
|
|
36
|
-
queryKey: (data?: ClientPayload<TInput, TVariables>) => (string | ClientPayload<TInput, TVariables>)[];
|
|
37
|
-
mutationKey: () => string[];
|
|
45
|
+
create: <TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.core.output<TOutputSchema>, TInput = z.core.output<TInputSchema>, TVariables = z.core.output<TVariablesSchema>>(opts: ClientOptions<TOutputSchema, TInputSchema, TVariablesSchema, TOutput, TInput, TVariables>) => ((_payload: OptionalPayload<ClientPayload<TInput, TVariables>>) => Promise<Result<TOutput, ClientError>>) & {
|
|
46
|
+
queryOptions: (_opts: object extends ClientPayload<TInput, TVariables> ? ReactQueryOptions<TOutput, TInput, TVariables> | void : ReactQueryOptions<TOutput, TInput, TVariables>) => UseQueryOptions<TOutput, ClientError>;
|
|
47
|
+
mutationOptions: (_opts: ReactMutationOptions<TOutput, TInput, TVariables> | void) => UseMutationOptions<TOutput, ClientError, object extends ClientPayload<TInput, TVariables> ? void : ClientPayload<TInput, TVariables>>;
|
|
38
48
|
config: {
|
|
39
49
|
inputSchema: undefined extends TInputSchema ? undefined : NonNullable<TInputSchema>;
|
|
40
50
|
variablesSchema: undefined extends TVariablesSchema ? undefined : NonNullable<TVariablesSchema>;
|
|
@@ -48,4 +58,24 @@ declare function createClient(axios: AxiosInstance): {
|
|
|
48
58
|
};
|
|
49
59
|
};
|
|
50
60
|
|
|
51
|
-
|
|
61
|
+
declare function callApi<TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.infer<TOutputSchema>, TInput = z.infer<TInputSchema>, TVariables = z.infer<TVariablesSchema>>(opts: ClientOptions<TOutputSchema, TInputSchema, TVariablesSchema, TOutput, TInput, TVariables> & {
|
|
62
|
+
axios: AxiosInstance;
|
|
63
|
+
}, data: ClientPayload<TInput, TVariables>): Promise<Result<TOutput, ClientError>>;
|
|
64
|
+
declare function getResponse<TOutputSchema extends z.ZodType, TInputSchema extends z.ZodType, TVariablesSchema extends z.ZodType, TOutput = z.infer<TOutputSchema>, TInput = z.infer<TInputSchema>, TVariables = z.infer<TVariablesSchema>>(request: Promise<AxiosResponse<TOutput>>, opts: ClientOptions<TOutputSchema, TInputSchema, TVariablesSchema, TOutput, TInput, TVariables>, payload: ClientPayload<TInput, TVariables>): Promise<Result<TOutput, ClientError>>;
|
|
65
|
+
|
|
66
|
+
declare const VALIDATION_ERROR_NAMES: {
|
|
67
|
+
readonly INPUT: "InputValidationError";
|
|
68
|
+
readonly VARIABLE: "VariableValidationError";
|
|
69
|
+
readonly OUTPUT: "OutputValidationError";
|
|
70
|
+
};
|
|
71
|
+
type ApiClientErrorProps = {
|
|
72
|
+
type: keyof typeof VALIDATION_ERROR_NAMES;
|
|
73
|
+
issues: z.core.$ZodIssue[];
|
|
74
|
+
};
|
|
75
|
+
declare class ValidationError extends ZodError {
|
|
76
|
+
constructor({ type, issues }: ApiClientErrorProps);
|
|
77
|
+
}
|
|
78
|
+
declare function ok<T>(data: T, response: AxiosResponse): Ok<T>;
|
|
79
|
+
declare function err<E>(error: E): Err<E>;
|
|
80
|
+
|
|
81
|
+
export { type ApiClientErrorProps, type ClientError, type ClientOptions, type ClientPayload, type Err, type Ok, type OptionalPayload, type ReactMutationOptions, type ReactQueryOptions, type Result, VALIDATION_ERROR_NAMES, ValidationError, callApi, createClient, err, getResponse, ok };
|
package/index.js
CHANGED
|
@@ -1,62 +1,5 @@
|
|
|
1
1
|
// src/lib/api-client.ts
|
|
2
2
|
import "zod";
|
|
3
|
-
|
|
4
|
-
// src/lib/call-api.ts
|
|
5
|
-
import "zod";
|
|
6
|
-
async function callApi(opts, data) {
|
|
7
|
-
if (typeof data !== "object")
|
|
8
|
-
throw new Error("API SDK: Data must be an object");
|
|
9
|
-
if (opts.inputSchema && "input" in data) {
|
|
10
|
-
opts.inputSchema.parse(data.input);
|
|
11
|
-
}
|
|
12
|
-
if (opts.variablesSchema && "variables" in data) {
|
|
13
|
-
opts.variablesSchema.parse(data.variables);
|
|
14
|
-
}
|
|
15
|
-
const axiosOptions = opts.axiosOptions?.(data);
|
|
16
|
-
const url = typeof opts.path === "function" ? opts.path(data) : opts.path;
|
|
17
|
-
if (opts.method === "GET") {
|
|
18
|
-
const response = await opts.axios.get(url, axiosOptions);
|
|
19
|
-
return getResponse(opts, data, response);
|
|
20
|
-
}
|
|
21
|
-
if (opts.method === "POST") {
|
|
22
|
-
const response = await opts.axios.post(
|
|
23
|
-
url,
|
|
24
|
-
axiosOptions?.data,
|
|
25
|
-
axiosOptions
|
|
26
|
-
);
|
|
27
|
-
return getResponse(opts, data, response);
|
|
28
|
-
}
|
|
29
|
-
if (opts.method === "PUT") {
|
|
30
|
-
const response = await opts.axios.put(
|
|
31
|
-
url,
|
|
32
|
-
axiosOptions?.data,
|
|
33
|
-
axiosOptions
|
|
34
|
-
);
|
|
35
|
-
return getResponse(opts, data, response);
|
|
36
|
-
}
|
|
37
|
-
if (opts.method === "PATCH") {
|
|
38
|
-
const response = await opts.axios.patch(
|
|
39
|
-
url,
|
|
40
|
-
axiosOptions?.data,
|
|
41
|
-
axiosOptions
|
|
42
|
-
);
|
|
43
|
-
return getResponse(opts, data, response);
|
|
44
|
-
}
|
|
45
|
-
if (opts.method === "DELETE") {
|
|
46
|
-
const response = await opts.axios.delete(url, axiosOptions);
|
|
47
|
-
return getResponse(opts, data, response);
|
|
48
|
-
}
|
|
49
|
-
throw new Error(`API SDK: Unsupported method: ${opts.method}`);
|
|
50
|
-
}
|
|
51
|
-
function getResponse(opts, payload, response) {
|
|
52
|
-
const parsedData = opts.outputSchema.parse(response.data);
|
|
53
|
-
if (opts.transform) {
|
|
54
|
-
return { ...response, data: opts.transform(parsedData, payload) };
|
|
55
|
-
}
|
|
56
|
-
return { ...response, data: parsedData };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// src/lib/api-client.ts
|
|
60
3
|
import "@tanstack/react-query";
|
|
61
4
|
function createClient(axios) {
|
|
62
5
|
function create(opts) {
|
|
@@ -73,14 +16,13 @@ function createClient(axios) {
|
|
|
73
16
|
const data = _data ?? {};
|
|
74
17
|
return {
|
|
75
18
|
queryFn: async () => {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
options.onSuccess?.(
|
|
79
|
-
return
|
|
80
|
-
} catch (error) {
|
|
81
|
-
options.onError?.(error, data);
|
|
82
|
-
throw error;
|
|
19
|
+
const result = await callApi(apiOptionas, data);
|
|
20
|
+
if (result.success) {
|
|
21
|
+
options.onSuccess?.(result.data, data);
|
|
22
|
+
return result.data;
|
|
83
23
|
}
|
|
24
|
+
options.onError?.(result.error, data);
|
|
25
|
+
throw result.error;
|
|
84
26
|
},
|
|
85
27
|
queryKey: queryKey(data),
|
|
86
28
|
...options
|
|
@@ -91,8 +33,9 @@ function createClient(axios) {
|
|
|
91
33
|
return {
|
|
92
34
|
mutationFn: async (_data) => {
|
|
93
35
|
const data = _data ?? {};
|
|
94
|
-
const
|
|
95
|
-
return
|
|
36
|
+
const result = await callApi(apiOptionas, data);
|
|
37
|
+
if (result.success) return result.data;
|
|
38
|
+
throw result.error;
|
|
96
39
|
},
|
|
97
40
|
mutationKey: mutationKey(),
|
|
98
41
|
...options
|
|
@@ -101,8 +44,6 @@ function createClient(axios) {
|
|
|
101
44
|
return Object.assign(call, {
|
|
102
45
|
queryOptions,
|
|
103
46
|
mutationOptions,
|
|
104
|
-
queryKey,
|
|
105
|
-
mutationKey,
|
|
106
47
|
config: {
|
|
107
48
|
...apiOptionas,
|
|
108
49
|
inputSchema: opts.inputSchema,
|
|
@@ -112,6 +53,116 @@ function createClient(axios) {
|
|
|
112
53
|
}
|
|
113
54
|
return { create };
|
|
114
55
|
}
|
|
56
|
+
|
|
57
|
+
// src/lib/call-api.ts
|
|
58
|
+
import "zod";
|
|
59
|
+
async function callApi(opts, data) {
|
|
60
|
+
if (typeof data !== "object")
|
|
61
|
+
throw new Error("API_CLIENT_INTERNAL_ERROR: Data must be an object");
|
|
62
|
+
if (opts.inputSchema && "input" in data) {
|
|
63
|
+
const parsedResult = opts.inputSchema.safeParse(data.input);
|
|
64
|
+
if (!parsedResult.success)
|
|
65
|
+
return err(
|
|
66
|
+
new ValidationError({
|
|
67
|
+
type: "INPUT",
|
|
68
|
+
issues: parsedResult.error.issues
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (opts.variablesSchema && "variables" in data) {
|
|
73
|
+
const parsedResult = opts.variablesSchema.safeParse(data.variables);
|
|
74
|
+
if (!parsedResult.success)
|
|
75
|
+
return err(
|
|
76
|
+
new ValidationError({
|
|
77
|
+
type: "VARIABLE",
|
|
78
|
+
issues: parsedResult.error.issues
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
const axiosOptions = opts.axiosOptions?.(data);
|
|
83
|
+
const url = typeof opts.path === "function" ? opts.path(data) : opts.path;
|
|
84
|
+
if (opts.method === "GET") {
|
|
85
|
+
return await getResponse(
|
|
86
|
+
opts.axios.get(url, axiosOptions),
|
|
87
|
+
opts,
|
|
88
|
+
data
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
if (opts.method === "POST") {
|
|
92
|
+
return await getResponse(
|
|
93
|
+
opts.axios.post(url, axiosOptions?.data, axiosOptions),
|
|
94
|
+
opts,
|
|
95
|
+
data
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
if (opts.method === "PUT") {
|
|
99
|
+
return await getResponse(
|
|
100
|
+
opts.axios.put(url, axiosOptions?.data, axiosOptions),
|
|
101
|
+
opts,
|
|
102
|
+
data
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (opts.method === "PATCH") {
|
|
106
|
+
return await getResponse(
|
|
107
|
+
opts.axios.patch(url, axiosOptions?.data, axiosOptions),
|
|
108
|
+
opts,
|
|
109
|
+
data
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
if (opts.method === "DELETE") {
|
|
113
|
+
return await getResponse(
|
|
114
|
+
opts.axios.delete(url, axiosOptions),
|
|
115
|
+
opts,
|
|
116
|
+
data
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
throw new Error(`API SDK: Unsupported method: ${opts.method}`);
|
|
120
|
+
}
|
|
121
|
+
async function getResponse(request, opts, payload) {
|
|
122
|
+
try {
|
|
123
|
+
const response = await request;
|
|
124
|
+
const parsedResult = opts.outputSchema.safeParse(response.data);
|
|
125
|
+
if (!parsedResult.success)
|
|
126
|
+
return err(
|
|
127
|
+
new ValidationError({
|
|
128
|
+
type: "OUTPUT",
|
|
129
|
+
issues: parsedResult.error.issues
|
|
130
|
+
})
|
|
131
|
+
);
|
|
132
|
+
if (opts.transform) {
|
|
133
|
+
return ok(opts.transform(parsedResult.data, payload), response);
|
|
134
|
+
}
|
|
135
|
+
return ok(parsedResult.data, response);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
return err(error);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/lib/result.ts
|
|
142
|
+
import { ZodError } from "zod";
|
|
143
|
+
var VALIDATION_ERROR_NAMES = {
|
|
144
|
+
INPUT: "InputValidationError",
|
|
145
|
+
VARIABLE: "VariableValidationError",
|
|
146
|
+
OUTPUT: "OutputValidationError"
|
|
147
|
+
};
|
|
148
|
+
var ValidationError = class extends ZodError {
|
|
149
|
+
constructor({ type, issues }) {
|
|
150
|
+
super(issues);
|
|
151
|
+
this.name = VALIDATION_ERROR_NAMES[type];
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
function ok(data, response) {
|
|
155
|
+
return { success: true, data, response };
|
|
156
|
+
}
|
|
157
|
+
function err(error) {
|
|
158
|
+
return { success: false, error };
|
|
159
|
+
}
|
|
115
160
|
export {
|
|
116
|
-
|
|
161
|
+
VALIDATION_ERROR_NAMES,
|
|
162
|
+
ValidationError,
|
|
163
|
+
callApi,
|
|
164
|
+
createClient,
|
|
165
|
+
err,
|
|
166
|
+
getResponse,
|
|
167
|
+
ok
|
|
117
168
|
};
|