add createApi

This commit is contained in:
Mohamadzadeh 2026-06-15 16:54:12 +03:30
parent cc19d8742a
commit 2f4a5f32f5
5 changed files with 487 additions and 506 deletions

743
dist/index.js vendored

File diff suppressed because one or more lines are too long

View File

@ -10,7 +10,7 @@ import {
let configuredApi = null;
export const createApi = (config) => {
const createApi = (config) => {
const { api } = config;
// instances

118
src/core/createApi.js Normal file
View File

@ -0,0 +1,118 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api, fetcher as defaultFetcher } from "./api.js";
function getBaseKey(key) {
return Array.isArray(key) ? key : [key];
}
function getListKey(key) {
return [...getBaseKey(key), "list"];
}
function getItemKey(key, id) {
return [...getBaseKey(key), id];
}
function buildUrl(url, params) {
if (!params) return url;
const searchParams = new URLSearchParams();
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
searchParams.append(key, value);
}
});
const query = searchParams.toString();
return query ? `${url}?${query}` : url;
}
function resolveUrl(url, data) {
if (typeof url === "function") {
return url(data?.id, data);
}
return url;
}
function omitId(data = {}) {
const { id, ...rest } = data;
return rest;
}
export function createApi({
key,
url,
actions = {},
axiosInstance = api,
fetcher = defaultFetcher,
}) {
const baseKey = getBaseKey(key);
const listKey = getListKey(key);
function useGet(params, options = {}) {
return useQuery({
queryKey: params ? [...listKey, params] : listKey,
queryFn: () => fetcher(buildUrl(url, params)),
...options,
});
}
function useAction(actionName, options = {}) {
const queryClient = useQueryClient();
const action = actions[actionName];
if (!action) {
throw new Error(`Action "${actionName}" is not defined.`);
}
return useMutation({
mutationKey: [...baseKey, actionName],
mutationFn: async (data = {}) => {
const method = action.method || "post";
const requestUrl = resolveUrl(action.url, data);
const payload = action.body
? action.body(data)
: action.withId
? data
: omitId(data);
const response = await axiosInstance[method](requestUrl, payload);
return response.data;
},
onSuccess: (...args) => {
const [responseData, variables] = args;
queryClient.invalidateQueries({
queryKey: listKey,
});
const id = variables?.id ?? responseData?.id;
if (id) {
queryClient.invalidateQueries({
queryKey: getItemKey(key, id),
});
}
options.onSuccess?.(...args);
},
...options,
});
}
return {
key: baseKey,
listKey,
useGet,
useAction,
};
}

View File

@ -1,124 +0,0 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { api, fetcher as defaultFetcher } from "./api";
function getListKey(key) {
return [`${key}-list`];
}
function buildUrl(url, params) {
if (!params) return url;
const searchParams = new URLSearchParams();
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
searchParams.append(key, value);
}
});
const query = searchParams.toString();
return query ? `${url}?${query}` : url;
}
function resolveUrl(url, data) {
return typeof url === "function" ? url(data) : url;
}
export function createCrud({
key,
url,
urls = {},
axiosInstance = api,
fetcher = defaultFetcher,
}) {
const listKey = getListKey(key);
const listUrl = urls.list || url;
const createUrl = urls.create || url;
const updateUrl = urls.update || ((id) => `${url}/${id}`);
const deleteUrl = urls.delete || ((id) => `${url}/${id}`);
function useGet(params, options = {}) {
return useQuery({
queryKey: params ? [...listKey, params] : listKey,
queryFn: () => {
const resolvedListUrl = resolveUrl(listUrl, params);
return fetcher(
typeof listUrl === "function"
? resolvedListUrl
: buildUrl(resolvedListUrl, params),
);
},
...options,
});
}
function useCreate(options = {}) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (payload) => axiosInstance.post(createUrl, payload),
onSuccess: (...args) => {
queryClient.invalidateQueries({
queryKey: listKey,
});
options.onSuccess?.(...args);
},
...options,
});
}
function useUpdate(options = {}) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, payload }) =>
axiosInstance.patch(resolveUrl(updateUrl, id), payload),
onSuccess: (...args) => {
queryClient.invalidateQueries({
queryKey: listKey,
});
options.onSuccess?.(...args);
},
...options,
});
}
function useDelete(options = {}) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id) => axiosInstance.delete(resolveUrl(deleteUrl, id)),
onSuccess: (...args) => {
queryClient.invalidateQueries({
queryKey: listKey,
});
options.onSuccess?.(...args);
},
...options,
});
}
return {
key,
listKey,
useGet,
useCreate,
useUpdate,
useDelete,
};
}

View File

@ -31,9 +31,9 @@ export {
getPermissions,
} from "./core/permission.jsx";
export { createApi, configureApi, getApi, api, fetcher } from "./core/api.js";
export { configureApi, getApi, api, fetcher } from "./core/api.js";
export { createCrud } from "./core/crud";
export { createApi } from "./core/createApi";
export { BiProvider } from "./provider/BiProvider.jsx";