Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | 1x 1x 1x | // src/utils/httpClient.js
import axios from "axios";
import { ApacuanaAPIError } from "../errors/index";
import { getConfig } from "../config/index";
let axiosInstance;
/**
* Inicializa el cliente HTTP (Axios) para todas las peticiones del SDK.
* @throws {Error} Si la configuración es incompleta.
*/
export const initHttpClient = () => {
const config = getConfig();
if (
!config.apiUrl ||
!config.secretKey ||
!config.apiKey ||
!config.verificationId ||
!config.customerId
) {
throw new Error(
"HttpClient: Configuración de inicialización incompleta. Llama a apacuana.init() primero."
);
}
axiosInstance = axios.create({
baseURL: config.apiUrl,
headers: {
"Content-Type": "application/json",
"APACUANA-API-Key": config.apiKey,
"APACUANA-SECRET-Key": config.secretKey,
// La cabecera Authorization se deja vacía al inicio.
// Se actualizará de forma dinámica con setAuthToken().
},
timeout: 30000,
});
// Configura los interceptores de Axios
axiosInstance.interceptors.response.use(
(response) => {
// Maneja errores lógicos de la API (si el backend devuelve status 2xx con { success: false })
if (response.data && response.data.success === false) {
throw new ApacuanaAPIError(
response.data.message ||
"Error lógico en la respuesta de la API (status 2xx)",
response.status,
response.data.code || "LOGICAL_API_ERROR"
);
}
return response;
},
(error) => {
// Maneja errores HTTP (status 4xx, 5xx) o errores de red
// eslint-disable-next-line no-console
console.error(
"[HTTP Client] Interceptor de error de Axios:",
error.response || error.message
);
if (error.response) {
const { status, data } = error.response;
throw new ApacuanaAPIError(
data.message || `Error en la API: ${status}`,
status,
data.code || "API_ERROR"
);
}
if (error.request) {
// La petición fue hecha, pero no se recibió respuesta (red caída, CORS, timeout)
throw new ApacuanaAPIError(
"Error de conexión a la red, timeout o CORS.",
0,
"NETWORK_ERROR"
);
} else {
// Algo más ocurrió al configurar la petición
throw new ApacuanaAPIError(
`Error desconocido en la petición: ${error.message}`,
0,
"UNKNOWN_REQUEST_ERROR"
);
}
}
);
// eslint-disable-next-line no-console
console.log(
"[HTTP Client] Cliente HTTP (Axios) REAL inicializado con URL base:",
config.apiUrl
);
};
/**
* Establece el token de autenticación Bearer para las peticiones subsiguientes.
* @param {string} token - El token de sesión del usuario.
* @throws {Error} Si el token es inválido o el cliente no está inicializado.
*/
export const setAuthToken = (token) => {
if (!axiosInstance) {
throw new Error(
"HttpClient no inicializado. Llama a apacuana.init() primero."
);
}
if (!token || typeof token !== "string") {
throw new Error("Token de sesión inválido.");
}
// Actualizamos la cabecera Authorization de la instancia de Axios.
axiosInstance.defaults.headers.common.Authorization = `Bearer ${token}`;
// eslint-disable-next-line no-console
console.log(
"[HTTP Client] Cabecera Authorization actualizada con nuevo token."
);
};
/**
* Envía una petición HTTP a un endpoint de la API.
* Inyecta automáticamente los parámetros de inicialización en el cuerpo de la petición.
* @param {string} path - La ruta del endpoint de la API.
* @param {object} [data={}] - Los datos para enviar en la petición.
* @param {string} [method='POST'] - El método HTTP.
* @returns {Promise<object>} Los datos de la respuesta del backend.
* @throws {ApacuanaAPIError} Si la petición falla.
*/
export const httpRequest = async (path, data = {}, method = "POST") => {
if (!axiosInstance) {
throw new Error(
"Apacuana SDK: Cliente HTTP no inicializado. " +
"Llama a apacuana.init() primero."
);
}
// Creamos el cuerpo de la petición fusionando los datos de la llamada
// con los parámetros de inicialización.
const dataToSend = {
...data,
};
// eslint-disable-next-line no-console
console.log(
`[HTTP Client] Realizando petición ${method} a: ${axiosInstance.defaults.baseURL}${path}`
);
// eslint-disable-next-line no-console
console.log(
"[HTTP Client] Headers (via Axios config):",
axiosInstance.defaults.headers
);
// eslint-disable-next-line no-console
console.log("[HTTP Client] Datos enviados:", dataToSend);
try {
let response;
switch (method.toUpperCase()) {
case "GET":
response = await axiosInstance.get(path, { params: dataToSend });
break;
case "POST":
response = await axiosInstance.post(path, dataToSend);
break;
case "PUT":
response = await axiosInstance.put(path, dataToSend);
break;
case "DELETE":
response = await axiosInstance.delete(path, { data: dataToSend });
break;
default:
throw new ApacuanaAPIError(
`Método HTTP no soportado: ${method}`,
405,
"UNSUPPORTED_HTTP_METHOD"
);
}
// Si la promesa se resolvió, la respuesta es exitosa.
// El interceptor ya manejó los errores 4xx/5xx y los errores lógicos 2xx.
// eslint-disable-next-line no-console
console.log(`[HTTP Client] Respuesta exitosa de ${path}:`, response.data);
return response.data;
} catch (error) {
// Si la petición falla, el interceptor ya procesó el error.
// Simplemente relanzamos el error para que sea capturado por la función de API.
// eslint-disable-next-line no-console
console.error(`[HTTP Client] Fallo en la petición a ${path}:`, error);
throw error;
}
};
|