Arreglo en cliente Axios

This commit is contained in:
David Arranz 2026-04-03 21:42:11 +02:00
parent 8b0b90f0ce
commit 699e097016
3 changed files with 87 additions and 93 deletions

View File

@ -1,5 +1,6 @@
import { createContext, useCallback, useContext, useEffect, useState } from "react";
import { UNSAFE_NavigationContext, useBeforeUnload, useBlocker } from "react-router-dom";
import { UnsavedChangesDialog } from "./components";
type ContextValue = {
@ -88,11 +89,10 @@ export function UnsavedChangesProvider({
};
}, [blocker, requestConfirm]);
return (
<UnsavedChangesContext.Provider value={{ requestConfirm }}>
{children}
<UnsavedChangesDialog open={open} onConfirm={handleConfirm} />
<UnsavedChangesDialog onConfirm={handleConfirm} open={open} />
</UnsavedChangesContext.Provider>
);
}

View File

@ -1,99 +1,100 @@
import type { AxiosInstance } from "axios";
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
import type { ICustomParams, IDataSource } from "../datasource.interface";
import { defaultAxiosRequestConfig } from "./create-axios-instance";
/**
* Crea un DataSource basado en Axios.
* @param client Instancia de Axios que se utilizará para las peticiones HTTP.
* @returns Un objeto que implementa la interfaz IDataSource.
* @throws Error si la instancia de Axios no es válida o no tiene la configuración necesaria.
* @example
* const axiosInstance = createAxiosInstance({
* baseURL: "https://api.example.com",
* getAccessToken: () => localStorage.getItem("accessToken"),
* onAuthError: () => {
* console.error("Error de autenticación");
* // Manejar el error de autenticación, por ejemplo, redirigir al login
* },
* });
* const dataSource = createAxiosDataSource(axiosInstance);
*
*/
export const createAxiosDataSource = (client: AxiosInstance): IDataSource => {
// Validaciones de la instancia de Axios
if (!client) {
throw new Error("[Axios] Se esperaba una instancia de Axios.");
}
if (!(client as AxiosInstance).getUri) {
if (!client.getUri || typeof client.getUri !== "function") {
throw new Error("[Axios] La instancia proporcionada no es una instancia de Axios válida.");
}
if (typeof (client as AxiosInstance).getUri !== "function") {
throw new Error("[Axios] La instancia proporcionada no tiene el método getUri.");
}
if (typeof (client as AxiosInstance).getUri() !== "string") {
if (typeof client.getUri() !== "string") {
throw new Error("[Axios] baseURL no está definido en esta instancia.");
}
return {
getBaseUrl: () => (client as AxiosInstance).getUri(),
getBaseUrl: () => client.getUri(),
getList: async <T>(resource: string, params?: Record<string, unknown>): Promise<T> => {
const { signal, ...rest } = params as any; // en 'rest' puede venir el "criteria".
getList: async <R>(resource: string, params?: Record<string, unknown>): Promise<R> => {
const { signal, ...rest } = (params ?? {}) as Record<string, unknown> & {
signal?: AbortSignal;
};
const res = await (client as AxiosInstance).get<T[]>(resource, { signal, params: rest });
return <T>res.data;
},
const res = await client.get<R>(resource, {
signal,
params: rest,
});
getOne: async <T>(resource: string, id: string | number, params?: Record<string, unknown>) => {
const res = await (client as AxiosInstance).get<T>(`${resource}/${id}`, params);
return res.data;
},
getMany: async <T, R>(resource: string, ids: Array<string | number>): Promise<R> => {
const res = await (client as AxiosInstance).get<T[]>(`${resource}`, { params: { ids } });
return <R>res.data;
},
createOne: async <T>(
resource: string,
data: Partial<T>,
params?: Record<string, unknown>
): Promise<T> => {
const res = await (client as AxiosInstance).post<T>(resource, data, params);
return res.data;
},
updateOne: async <T>(
resource: string,
id: string | number,
data: Partial<T>,
params?: Record<string, unknown>
) => {
const res = await (client as AxiosInstance).put<T>(`${resource}/${id}`, data, params);
return res.data;
},
deleteOne: async <T>(
getOne: async <R>(
resource: string,
id: string | number,
params?: Record<string, unknown>
) => {
await (client as AxiosInstance).delete(`${resource}/${id}`, params);
): Promise<R> => {
const res = await client.get<R>(`${resource}/${id}`, params);
return res.data;
},
custom: async <T>(customParams: ICustomParams) => {
getMany: async <R>(resource: string, ids: Array<string | number>): Promise<R> => {
const res = await client.get<R>(resource, {
params: { ids },
});
return res.data;
},
createOne: async <TData, R>(
resource: string,
data: TData,
params?: Record<string, unknown>
): Promise<R> => {
const res = await client.post<R, AxiosResponse<R>, TData>(
resource,
data,
params as AxiosRequestConfig<TData>
);
return res.data;
},
updateOne: async <TData, R>(
resource: string,
id: string | number,
data: TData,
params?: Record<string, unknown>
): Promise<R> => {
const res = await client.put<R, AxiosResponse<R>, TData>(
`${resource}/${id}`,
data,
params as AxiosRequestConfig<TData>
);
return res.data;
},
deleteOne: async <R = void>(
resource: string,
id: string | number,
params?: Record<string, unknown>
): Promise<R> => {
const res = await client.delete<R>(`${resource}/${id}`, params);
return res.data;
},
custom: async <TData, R>(customParams: ICustomParams<TData>): Promise<R> => {
const { url, path, method, responseType, headers, signal, data, ...payload } = customParams;
const requestUrl = path ? `${(client as AxiosInstance).getUri()}/${path}` : url;
const requestUrl = path ? `${client.getUri()}/${path}` : url;
if (!requestUrl) throw new Error('"url" or "path" param is missing');
const config = {
const config: AxiosRequestConfig<TData> = {
url: requestUrl,
method,
responseType,
@ -103,32 +104,27 @@ export const createAxiosDataSource = (client: AxiosInstance): IDataSource => {
headers,
};
let customResponse;
let customResponse: AxiosResponse<R, TData>;
switch (method) {
case "put":
case "post":
case "patch":
customResponse = await (client as AxiosInstance).request<T>({
customResponse = await client.request<R, AxiosResponse<R>, TData>({
...config,
data,
});
break;
case "delete":
customResponse = await (client as AxiosInstance).delete<T>(requestUrl, {
responseType,
headers,
...payload,
customResponse = await client.delete<R, AxiosResponse<R>, TData>(requestUrl, {
...config,
});
break;
default:
customResponse = await (client as AxiosInstance).get<T>(requestUrl, {
responseType,
signal,
headers,
...payload,
customResponse = await client.get<R, AxiosResponse<R>, TData>(requestUrl, {
...config,
});
break;
}

View File

@ -1,34 +1,32 @@
import type { ResponseType } from "axios";
import type { AxiosRequestConfig, ResponseType } from "axios";
export interface ICustomParams {
export interface ICustomParams<T> {
url?: string;
path?: string;
method: "get" | "delete" | "head" | "options" | "post" | "put" | "patch";
signal?: AbortSignal;
responseType?: ResponseType;
headers?: {
[key: string]: unknown;
};
headers?: AxiosRequestConfig<T>["headers"];
data: T;
[key: string]: unknown;
}
export interface IDataSource {
getBaseUrl(): string;
getList<T>(resource: string, params?: Record<string, unknown>): Promise<T>;
getOne<T>(resource: string, id: string | number, params?: Record<string, unknown>): Promise<T>;
getMany<T, R>(resource: string, ids: Array<string | number>): Promise<R>;
createOne<T>(resource: string, data: Partial<T>, params?: Record<string, unknown>): Promise<T>;
updateOne<T>(
getList<R>(resource: string, params?: Record<string, unknown>): Promise<R>;
getOne<R>(resource: string, id: string | number, params?: Record<string, unknown>): Promise<R>;
getMany<R>(resource: string, ids: Array<string | number>): Promise<R[]>;
createOne<TData, R>(resource: string, data: TData, params?: Record<string, unknown>): Promise<R>;
updateOne<TData, R>(
resource: string,
id: string | number,
data: Partial<T>,
data: TData,
params?: Record<string, unknown>
): Promise<T>;
deleteOne<T>(
): Promise<R>;
deleteOne<R = void>(
resource: string,
id: string | number,
params?: Record<string, unknown>
): Promise<void>;
custom: <R>(customParams: ICustomParams) => Promise<R>;
): Promise<R>;
custom<TData, R>(customParams: ICustomParams<TData>): Promise<R>;
}