@ahsan-iftikhar-114/api-toolkit-react-query 1.0.0
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/LICENSE.md +21 -0
- package/README.md +1017 -0
- package/dist/config/config.d.ts +12 -0
- package/dist/config/config.js +29 -0
- package/dist/core/api.d.ts +26 -0
- package/dist/core/api.js +88 -0
- package/dist/core/axios.d.ts +10 -0
- package/dist/core/axios.js +38 -0
- package/dist/core/cache.d.ts +20 -0
- package/dist/core/cache.js +39 -0
- package/dist/core/client.d.ts +8 -0
- package/dist/core/client.js +10 -0
- package/dist/core/error.d.ts +6 -0
- package/dist/core/error.js +36 -0
- package/dist/core/mutation.d.ts +13 -0
- package/dist/core/mutation.js +27 -0
- package/dist/core/query.d.ts +10 -0
- package/dist/core/query.js +28 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +41 -0
- package/dist/types/index.d.ts +97 -0
- package/dist/types/index.js +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ApiConfig } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Configure global API settings.
|
|
4
|
+
*
|
|
5
|
+
* Request-level configuration can override
|
|
6
|
+
* these settings.
|
|
7
|
+
*/
|
|
8
|
+
export declare const configureApi: (config: ApiConfig) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Get current global API configuration.
|
|
11
|
+
*/
|
|
12
|
+
export declare const getApiConfig: () => ApiConfig;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
let apiConfig = {
|
|
2
|
+
baseURL: "",
|
|
3
|
+
timeout: 30000,
|
|
4
|
+
headers: {
|
|
5
|
+
"Content-Type": "application/json",
|
|
6
|
+
},
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Configure global API settings.
|
|
10
|
+
*
|
|
11
|
+
* Request-level configuration can override
|
|
12
|
+
* these settings.
|
|
13
|
+
*/
|
|
14
|
+
export const configureApi = (config) => {
|
|
15
|
+
apiConfig = {
|
|
16
|
+
...apiConfig,
|
|
17
|
+
...config,
|
|
18
|
+
headers: {
|
|
19
|
+
...apiConfig.headers,
|
|
20
|
+
...config.headers,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Get current global API configuration.
|
|
26
|
+
*/
|
|
27
|
+
export const getApiConfig = () => {
|
|
28
|
+
return apiConfig;
|
|
29
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AxiosResponse } from "axios";
|
|
2
|
+
import { ApiMethod, ApiRequestPayload } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* Generic API request.
|
|
5
|
+
*/
|
|
6
|
+
export declare const apiRequest: <TResponse = unknown, TRequest = unknown>(method: ApiMethod, url: string, payload?: ApiRequestPayload<TRequest>) => Promise<AxiosResponse<TResponse, any, {}, any>>;
|
|
7
|
+
/**
|
|
8
|
+
* GET request.
|
|
9
|
+
*/
|
|
10
|
+
export declare const apiGet: <TResponse = unknown>(url: string, payload?: ApiRequestPayload) => Promise<AxiosResponse<TResponse, any, {}, any>>;
|
|
11
|
+
/**
|
|
12
|
+
* POST request.
|
|
13
|
+
*/
|
|
14
|
+
export declare const apiPost: <TResponse = unknown, TRequest = unknown>(url: string, payload?: ApiRequestPayload<TRequest>) => Promise<AxiosResponse<TResponse, any, {}, any>>;
|
|
15
|
+
/**
|
|
16
|
+
* PUT request.
|
|
17
|
+
*/
|
|
18
|
+
export declare const apiPut: <TResponse = unknown, TRequest = unknown>(url: string, payload?: ApiRequestPayload<TRequest>) => Promise<AxiosResponse<TResponse, any, {}, any>>;
|
|
19
|
+
/**
|
|
20
|
+
* PATCH request.
|
|
21
|
+
*/
|
|
22
|
+
export declare const apiPatch: <TResponse = unknown, TRequest = unknown>(url: string, payload?: ApiRequestPayload<TRequest>) => Promise<AxiosResponse<TResponse, any, {}, any>>;
|
|
23
|
+
/**
|
|
24
|
+
* DELETE request.
|
|
25
|
+
*/
|
|
26
|
+
export declare const apiDelete: <TResponse = unknown, TRequest = unknown>(url: string, payload?: ApiRequestPayload<TRequest>) => Promise<AxiosResponse<TResponse, any, {}, any>>;
|
package/dist/core/api.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { getAxiosInstance, } from "./axios";
|
|
3
|
+
import { normalizeApiError, } from "./error";
|
|
4
|
+
const request = async (method, url, payload) => {
|
|
5
|
+
const axiosInstance = getAxiosInstance();
|
|
6
|
+
const config = {
|
|
7
|
+
...(payload?.config || {}),
|
|
8
|
+
...(payload?.params !== undefined
|
|
9
|
+
? {
|
|
10
|
+
params: payload.params,
|
|
11
|
+
}
|
|
12
|
+
: {}),
|
|
13
|
+
...(payload?.headers !== undefined
|
|
14
|
+
? {
|
|
15
|
+
headers: payload.headers,
|
|
16
|
+
}
|
|
17
|
+
: {}),
|
|
18
|
+
...(payload?.signal !== undefined
|
|
19
|
+
? {
|
|
20
|
+
signal: payload.signal,
|
|
21
|
+
}
|
|
22
|
+
: {}),
|
|
23
|
+
};
|
|
24
|
+
try {
|
|
25
|
+
switch (method) {
|
|
26
|
+
case "GET":
|
|
27
|
+
return await axiosInstance.get(url, config);
|
|
28
|
+
case "POST":
|
|
29
|
+
return await axiosInstance.post(url, payload?.data, config);
|
|
30
|
+
case "PUT":
|
|
31
|
+
return await axiosInstance.put(url, payload?.data, config);
|
|
32
|
+
case "PATCH":
|
|
33
|
+
return await axiosInstance.patch(url, payload?.data, config);
|
|
34
|
+
case "DELETE":
|
|
35
|
+
return await axiosInstance.delete(url, {
|
|
36
|
+
...config,
|
|
37
|
+
data: payload?.data,
|
|
38
|
+
});
|
|
39
|
+
default:
|
|
40
|
+
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
/**
|
|
45
|
+
* Preserve Axios cancellation errors.
|
|
46
|
+
*/
|
|
47
|
+
if (axios.isCancel(error)) {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
throw normalizeApiError(error);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Generic API request.
|
|
55
|
+
*/
|
|
56
|
+
export const apiRequest = (method, url, payload) => {
|
|
57
|
+
return request(method, url, payload);
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* GET request.
|
|
61
|
+
*/
|
|
62
|
+
export const apiGet = (url, payload) => {
|
|
63
|
+
return request("GET", url, payload);
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* POST request.
|
|
67
|
+
*/
|
|
68
|
+
export const apiPost = (url, payload) => {
|
|
69
|
+
return request("POST", url, payload);
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* PUT request.
|
|
73
|
+
*/
|
|
74
|
+
export const apiPut = (url, payload) => {
|
|
75
|
+
return request("PUT", url, payload);
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* PATCH request.
|
|
79
|
+
*/
|
|
80
|
+
export const apiPatch = (url, payload) => {
|
|
81
|
+
return request("PATCH", url, payload);
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* DELETE request.
|
|
85
|
+
*/
|
|
86
|
+
export const apiDelete = (url, payload) => {
|
|
87
|
+
return request("DELETE", url, payload);
|
|
88
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AxiosInstance } from "axios";
|
|
2
|
+
/**
|
|
3
|
+
* Initialize Axios using the
|
|
4
|
+
* current global API configuration.
|
|
5
|
+
*/
|
|
6
|
+
export declare const initializeAxios: () => AxiosInstance;
|
|
7
|
+
/**
|
|
8
|
+
* Get the current Axios instance.
|
|
9
|
+
*/
|
|
10
|
+
export declare const getAxiosInstance: () => AxiosInstance;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { getApiConfig, } from "../config/config";
|
|
3
|
+
let axiosInstance = axios.create();
|
|
4
|
+
/**
|
|
5
|
+
* Initialize Axios using the
|
|
6
|
+
* current global API configuration.
|
|
7
|
+
*/
|
|
8
|
+
export const initializeAxios = () => {
|
|
9
|
+
const config = getApiConfig();
|
|
10
|
+
axiosInstance = axios.create({
|
|
11
|
+
baseURL: config.baseURL,
|
|
12
|
+
timeout: config.timeout,
|
|
13
|
+
headers: config.headers,
|
|
14
|
+
});
|
|
15
|
+
axiosInstance.interceptors.request.use((request) => {
|
|
16
|
+
const currentConfig = getApiConfig();
|
|
17
|
+
if (currentConfig.token) {
|
|
18
|
+
const token = typeof currentConfig.token ===
|
|
19
|
+
"function"
|
|
20
|
+
? currentConfig.token()
|
|
21
|
+
: currentConfig.token;
|
|
22
|
+
if (token) {
|
|
23
|
+
request.headers.Authorization =
|
|
24
|
+
`Bearer ${token}`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return request;
|
|
28
|
+
}, (error) => {
|
|
29
|
+
return Promise.reject(error);
|
|
30
|
+
});
|
|
31
|
+
return axiosInstance;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Get the current Axios instance.
|
|
35
|
+
*/
|
|
36
|
+
export const getAxiosInstance = () => {
|
|
37
|
+
return axiosInstance;
|
|
38
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
+
/**
|
|
3
|
+
* Invalidate all queries belonging
|
|
4
|
+
* to a specific API name.
|
|
5
|
+
*/
|
|
6
|
+
export declare const invalidateApi: (name: string, queryClient: QueryClient) => Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Invalidate multiple APIs.
|
|
9
|
+
*/
|
|
10
|
+
export declare const invalidateApis: (names: string[], queryClient: QueryClient) => Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Invalidate every query
|
|
13
|
+
* in the provided QueryClient.
|
|
14
|
+
*/
|
|
15
|
+
export declare const invalidateAllApis: (queryClient: QueryClient) => Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Cancel all queries belonging
|
|
18
|
+
* to a specific API name.
|
|
19
|
+
*/
|
|
20
|
+
export declare const cancelApi: (name: string, queryClient: QueryClient) => Promise<void>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Invalidate all queries belonging
|
|
3
|
+
* to a specific API name.
|
|
4
|
+
*/
|
|
5
|
+
export const invalidateApi = async (name, queryClient) => {
|
|
6
|
+
await queryClient.invalidateQueries({
|
|
7
|
+
queryKey: [
|
|
8
|
+
name,
|
|
9
|
+
],
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Invalidate multiple APIs.
|
|
14
|
+
*/
|
|
15
|
+
export const invalidateApis = async (names, queryClient) => {
|
|
16
|
+
await Promise.all(names.map((name) => queryClient.invalidateQueries({
|
|
17
|
+
queryKey: [
|
|
18
|
+
name,
|
|
19
|
+
],
|
|
20
|
+
})));
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Invalidate every query
|
|
24
|
+
* in the provided QueryClient.
|
|
25
|
+
*/
|
|
26
|
+
export const invalidateAllApis = async (queryClient) => {
|
|
27
|
+
await queryClient.invalidateQueries();
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Cancel all queries belonging
|
|
31
|
+
* to a specific API name.
|
|
32
|
+
*/
|
|
33
|
+
export const cancelApi = async (name, queryClient) => {
|
|
34
|
+
await queryClient.cancelQueries({
|
|
35
|
+
queryKey: [
|
|
36
|
+
name,
|
|
37
|
+
],
|
|
38
|
+
});
|
|
39
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { QueryClient, QueryClientConfig } from "@tanstack/react-query";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a QueryClient for the application.
|
|
4
|
+
*
|
|
5
|
+
* The package does not maintain a global
|
|
6
|
+
* QueryClient instance.
|
|
7
|
+
*/
|
|
8
|
+
export declare const createApiQueryClient: (options?: QueryClientConfig) => QueryClient;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { QueryClient, } from "@tanstack/react-query";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a QueryClient for the application.
|
|
4
|
+
*
|
|
5
|
+
* The package does not maintain a global
|
|
6
|
+
* QueryClient instance.
|
|
7
|
+
*/
|
|
8
|
+
export const createApiQueryClient = (options) => {
|
|
9
|
+
return new QueryClient(options);
|
|
10
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
/**
|
|
3
|
+
* Normalize unknown API errors
|
|
4
|
+
* into a consistent ApiError structure.
|
|
5
|
+
*/
|
|
6
|
+
export const normalizeApiError = (error) => {
|
|
7
|
+
if (axios.isAxiosError(error)) {
|
|
8
|
+
const responseData = error.response?.data;
|
|
9
|
+
const dataObject = typeof responseData === "object" &&
|
|
10
|
+
responseData !== null
|
|
11
|
+
? responseData
|
|
12
|
+
: undefined;
|
|
13
|
+
const message = typeof dataObject?.message === "string"
|
|
14
|
+
? dataObject.message
|
|
15
|
+
: error.message ||
|
|
16
|
+
"Something went wrong";
|
|
17
|
+
return {
|
|
18
|
+
message,
|
|
19
|
+
status: error.response?.status,
|
|
20
|
+
statusText: error.response?.statusText,
|
|
21
|
+
data: responseData,
|
|
22
|
+
errors: dataObject?.errors,
|
|
23
|
+
originalError: error,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (error instanceof Error) {
|
|
27
|
+
return {
|
|
28
|
+
message: error.message,
|
|
29
|
+
originalError: error,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
message: "Something went wrong",
|
|
34
|
+
originalError: error,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { UseMutationResult } from "@tanstack/react-query";
|
|
2
|
+
import { ApiMethod, ApiRequestPayload, ApiMutationOptions, ApiError } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a reusable mutation API hook.
|
|
5
|
+
*
|
|
6
|
+
* Supports:
|
|
7
|
+
*
|
|
8
|
+
* POST
|
|
9
|
+
* PUT
|
|
10
|
+
* PATCH
|
|
11
|
+
* DELETE
|
|
12
|
+
*/
|
|
13
|
+
export declare const createApiMutation: <TResponse = unknown, TRequest = unknown, TContext = unknown>(name: string, method: Exclude<ApiMethod, "GET">, url: string) => (options?: ApiMutationOptions<TResponse, TRequest, TContext>) => UseMutationResult<TResponse, ApiError, ApiRequestPayload<TRequest>, TContext>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useMutation, } from "@tanstack/react-query";
|
|
2
|
+
import { apiRequest, } from "./api";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a reusable mutation API hook.
|
|
5
|
+
*
|
|
6
|
+
* Supports:
|
|
7
|
+
*
|
|
8
|
+
* POST
|
|
9
|
+
* PUT
|
|
10
|
+
* PATCH
|
|
11
|
+
* DELETE
|
|
12
|
+
*/
|
|
13
|
+
export const createApiMutation = (name, method, url) => {
|
|
14
|
+
return (options) => {
|
|
15
|
+
return useMutation({
|
|
16
|
+
...options,
|
|
17
|
+
mutationKey: [
|
|
18
|
+
name,
|
|
19
|
+
url,
|
|
20
|
+
],
|
|
21
|
+
mutationFn: async (payload) => {
|
|
22
|
+
const response = await apiRequest(method, url, payload);
|
|
23
|
+
return response.data;
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { UseQueryResult } from "@tanstack/react-query";
|
|
2
|
+
import { ApiRequestPayload, ApiQueryOptions, ApiError } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a reusable GET API query hook.
|
|
5
|
+
*
|
|
6
|
+
* Supports all standard TanStack Query options,
|
|
7
|
+
* except queryKey and queryFn which are managed
|
|
8
|
+
* internally by this package.
|
|
9
|
+
*/
|
|
10
|
+
export declare const createApiQuery: <TResponse = unknown>(name: string, url: string) => <TData = TResponse>(payload?: ApiRequestPayload, options?: ApiQueryOptions<TResponse, TData>) => UseQueryResult<TData, ApiError>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { useQuery, } from "@tanstack/react-query";
|
|
2
|
+
import { apiRequest, } from "./api";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a reusable GET API query hook.
|
|
5
|
+
*
|
|
6
|
+
* Supports all standard TanStack Query options,
|
|
7
|
+
* except queryKey and queryFn which are managed
|
|
8
|
+
* internally by this package.
|
|
9
|
+
*/
|
|
10
|
+
export const createApiQuery = (name, url) => {
|
|
11
|
+
return (payload, options) => {
|
|
12
|
+
return useQuery({
|
|
13
|
+
...options,
|
|
14
|
+
queryKey: [
|
|
15
|
+
name,
|
|
16
|
+
url,
|
|
17
|
+
payload?.params,
|
|
18
|
+
],
|
|
19
|
+
queryFn: async ({ signal, }) => {
|
|
20
|
+
const response = await apiRequest("GET", url, {
|
|
21
|
+
...payload,
|
|
22
|
+
signal,
|
|
23
|
+
});
|
|
24
|
+
return response.data;
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createApiQueryClient } from "./core/client";
|
|
2
|
+
import { invalidateApi, invalidateApis, invalidateAllApis, cancelApi } from "./core/cache";
|
|
3
|
+
import { ApiMethod, ApiRequestPayload, ApiConfig, ApiQueryOptions, ApiMutationOptions, ApiError, ApiResponse, ApiRequestDefinition } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* Public types.
|
|
6
|
+
*/
|
|
7
|
+
export type { ApiMethod, ApiRequestPayload, ApiConfig, ApiQueryOptions, ApiMutationOptions, ApiError, ApiResponse, ApiRequestDefinition, };
|
|
8
|
+
/**
|
|
9
|
+
* Public utilities.
|
|
10
|
+
*/
|
|
11
|
+
export { createApiQueryClient, invalidateApi, invalidateApis, invalidateAllApis, cancelApi, };
|
|
12
|
+
/**
|
|
13
|
+
* Configure global API settings.
|
|
14
|
+
*/
|
|
15
|
+
export declare const configureApi: (config: ApiConfig) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Create a generic API hook.
|
|
18
|
+
*
|
|
19
|
+
* GET:
|
|
20
|
+
* React Query query
|
|
21
|
+
*
|
|
22
|
+
* POST:
|
|
23
|
+
* React Query mutation
|
|
24
|
+
*
|
|
25
|
+
* PUT:
|
|
26
|
+
* React Query mutation
|
|
27
|
+
*
|
|
28
|
+
* PATCH:
|
|
29
|
+
* React Query mutation
|
|
30
|
+
*
|
|
31
|
+
* DELETE:
|
|
32
|
+
* React Query mutation
|
|
33
|
+
*/
|
|
34
|
+
export declare const createApi: <TResponse = unknown, TRequest = unknown, TContext = unknown>(name: string, method: ApiMethod, url: string) => (<TData = TResponse>(payload?: ApiRequestPayload, options?: ApiQueryOptions<TResponse, TData> | undefined) => import("@tanstack/react-query").UseQueryResult<TData, ApiError>) | ((options?: ApiMutationOptions<TResponse, TRequest, TContext> | undefined) => import("@tanstack/react-query").UseMutationResult<TResponse, ApiError, ApiRequestPayload<TRequest>, TContext>);
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { configureApi as configureApiConfig, } from "./config/config";
|
|
2
|
+
import { initializeAxios, } from "./core/axios";
|
|
3
|
+
import { createApiQuery, } from "./core/query";
|
|
4
|
+
import { createApiMutation, } from "./core/mutation";
|
|
5
|
+
import { createApiQueryClient, } from "./core/client";
|
|
6
|
+
import { invalidateApi, invalidateApis, invalidateAllApis, cancelApi, } from "./core/cache";
|
|
7
|
+
/**
|
|
8
|
+
* Public utilities.
|
|
9
|
+
*/
|
|
10
|
+
export { createApiQueryClient, invalidateApi, invalidateApis, invalidateAllApis, cancelApi, };
|
|
11
|
+
/**
|
|
12
|
+
* Configure global API settings.
|
|
13
|
+
*/
|
|
14
|
+
export const configureApi = (config) => {
|
|
15
|
+
configureApiConfig(config);
|
|
16
|
+
initializeAxios();
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Create a generic API hook.
|
|
20
|
+
*
|
|
21
|
+
* GET:
|
|
22
|
+
* React Query query
|
|
23
|
+
*
|
|
24
|
+
* POST:
|
|
25
|
+
* React Query mutation
|
|
26
|
+
*
|
|
27
|
+
* PUT:
|
|
28
|
+
* React Query mutation
|
|
29
|
+
*
|
|
30
|
+
* PATCH:
|
|
31
|
+
* React Query mutation
|
|
32
|
+
*
|
|
33
|
+
* DELETE:
|
|
34
|
+
* React Query mutation
|
|
35
|
+
*/
|
|
36
|
+
export const createApi = (name, method, url) => {
|
|
37
|
+
if (method === "GET") {
|
|
38
|
+
return createApiQuery(name, url);
|
|
39
|
+
}
|
|
40
|
+
return createApiMutation(name, method, url);
|
|
41
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { AxiosRequestConfig, AxiosResponse } from "axios";
|
|
2
|
+
import type { UseQueryOptions, UseMutationOptions, QueryKey } from "@tanstack/react-query";
|
|
3
|
+
export type ApiMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
4
|
+
/**
|
|
5
|
+
* Generic API request payload.
|
|
6
|
+
*/
|
|
7
|
+
export interface ApiRequestPayload<TRequest = unknown> {
|
|
8
|
+
/**
|
|
9
|
+
* Request body.
|
|
10
|
+
*
|
|
11
|
+
* Used by POST, PUT, PATCH and DELETE.
|
|
12
|
+
*/
|
|
13
|
+
data?: TRequest;
|
|
14
|
+
/**
|
|
15
|
+
* URL query parameters.
|
|
16
|
+
*/
|
|
17
|
+
params?: Record<string, unknown>;
|
|
18
|
+
/**
|
|
19
|
+
* Request-specific headers.
|
|
20
|
+
*/
|
|
21
|
+
headers?: Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Advanced Axios configuration.
|
|
24
|
+
*/
|
|
25
|
+
config?: AxiosRequestConfig;
|
|
26
|
+
/**
|
|
27
|
+
* Request cancellation signal.
|
|
28
|
+
*/
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Global API configuration.
|
|
33
|
+
*/
|
|
34
|
+
export interface ApiConfig {
|
|
35
|
+
/**
|
|
36
|
+
* Base API URL.
|
|
37
|
+
*/
|
|
38
|
+
baseURL?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Global request timeout in milliseconds.
|
|
41
|
+
*/
|
|
42
|
+
timeout?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Global request headers.
|
|
45
|
+
*/
|
|
46
|
+
headers?: Record<string, string>;
|
|
47
|
+
/**
|
|
48
|
+
* Authentication token.
|
|
49
|
+
*
|
|
50
|
+
* Can be a static token or a function
|
|
51
|
+
* returning the latest token.
|
|
52
|
+
*/
|
|
53
|
+
token?: string | (() => string | null | undefined);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Normalized API error.
|
|
57
|
+
*/
|
|
58
|
+
export interface ApiError {
|
|
59
|
+
message: string;
|
|
60
|
+
status?: number;
|
|
61
|
+
statusText?: string;
|
|
62
|
+
data?: unknown;
|
|
63
|
+
errors?: unknown;
|
|
64
|
+
originalError?: unknown;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Standard API response.
|
|
68
|
+
*/
|
|
69
|
+
export interface ApiResponse<TResponse = unknown> {
|
|
70
|
+
data: TResponse;
|
|
71
|
+
status: number;
|
|
72
|
+
statusText: string;
|
|
73
|
+
headers: unknown;
|
|
74
|
+
response: AxiosResponse<TResponse>;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* API definition.
|
|
78
|
+
*/
|
|
79
|
+
export interface ApiRequestDefinition {
|
|
80
|
+
name: string;
|
|
81
|
+
method: ApiMethod;
|
|
82
|
+
url: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Advanced React Query options.
|
|
86
|
+
*
|
|
87
|
+
* TQueryFnData:
|
|
88
|
+
* Actual API response.
|
|
89
|
+
*
|
|
90
|
+
* TData:
|
|
91
|
+
* Data returned after select().
|
|
92
|
+
*/
|
|
93
|
+
export type ApiQueryOptions<TQueryFnData = unknown, TData = TQueryFnData> = Omit<UseQueryOptions<TQueryFnData, ApiError, TData, QueryKey>, "queryKey" | "queryFn">;
|
|
94
|
+
/**
|
|
95
|
+
* Advanced React Query mutation options.
|
|
96
|
+
*/
|
|
97
|
+
export type ApiMutationOptions<TResponse = unknown, TRequest = unknown, TContext = unknown> = Omit<UseMutationOptions<TResponse, ApiError, ApiRequestPayload<TRequest>, TContext>, "mutationKey" | "mutationFn">;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ahsan-iftikhar-114/api-toolkit-react-query",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A generic API toolkit for React applications using Axios and TanStack Query.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"react",
|
|
18
|
+
"react-query",
|
|
19
|
+
"tanstack-query",
|
|
20
|
+
"axios",
|
|
21
|
+
"typescript",
|
|
22
|
+
"api",
|
|
23
|
+
"api-client",
|
|
24
|
+
"react-api",
|
|
25
|
+
"react-api-client",
|
|
26
|
+
"react-query-axios",
|
|
27
|
+
"tanstack-query-axios",
|
|
28
|
+
"axios-react-query",
|
|
29
|
+
"api-toolkit",
|
|
30
|
+
"api-hooks",
|
|
31
|
+
"react-hooks",
|
|
32
|
+
"query-hooks",
|
|
33
|
+
"mutation-hooks",
|
|
34
|
+
"rest-api",
|
|
35
|
+
"rest-api-client",
|
|
36
|
+
"typescript-api-client",
|
|
37
|
+
"api-cache",
|
|
38
|
+
"cache-invalidation",
|
|
39
|
+
"request-cancellation",
|
|
40
|
+
"react-query-cache",
|
|
41
|
+
"react-query-typescript",
|
|
42
|
+
"axios-typescript"
|
|
43
|
+
],
|
|
44
|
+
"author": "Ahsan Iftikhar",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@tanstack/react-query": "^5.0.0",
|
|
48
|
+
"react": ">=18.0.0"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"axios": "^1.0.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@tanstack/react-query": "^5.0.0",
|
|
55
|
+
"@types/react": "^19.0.0",
|
|
56
|
+
"@types/react-dom": "^19.0.0",
|
|
57
|
+
"typescript": "^5.0.0"
|
|
58
|
+
}
|
|
59
|
+
}
|