2024-07-24 23:20:45 +03:00
|
|
|
/**
|
2025-01-28 19:45:31 +03:00
|
|
|
* Module: generic API for backend REST communications using axios library.
|
2024-07-24 23:20:45 +03:00
|
|
|
*/
|
|
|
|
import { toast } from 'react-toastify';
|
2025-02-12 21:36:03 +03:00
|
|
|
import axios, { AxiosError, AxiosRequestConfig } from 'axios';
|
2025-02-17 14:31:17 +03:00
|
|
|
import { z, ZodError } from 'zod';
|
2024-07-24 23:20:45 +03:00
|
|
|
|
2025-01-28 19:45:31 +03:00
|
|
|
import { buildConstants } from '@/utils/buildConstants';
|
2025-02-17 14:31:17 +03:00
|
|
|
import { errorMsg } from '@/utils/labels';
|
2024-08-18 12:55:41 +03:00
|
|
|
import { extractErrorMessage } from '@/utils/utils';
|
2024-07-24 23:20:45 +03:00
|
|
|
|
2025-02-10 01:32:16 +03:00
|
|
|
export { AxiosError } from 'axios';
|
|
|
|
export const isAxiosError = axios.isAxiosError;
|
|
|
|
|
2025-01-28 19:45:31 +03:00
|
|
|
const defaultOptions = {
|
|
|
|
xsrfCookieName: 'csrftoken',
|
|
|
|
xsrfHeaderName: 'x-csrftoken',
|
|
|
|
baseURL: `${buildConstants.backend}`,
|
|
|
|
withCredentials: true
|
|
|
|
};
|
|
|
|
|
|
|
|
const axiosInstance = axios.create(defaultOptions);
|
|
|
|
axiosInstance.interceptors.request.use(config => {
|
|
|
|
const token = document.cookie
|
|
|
|
.split('; ')
|
|
|
|
.find(row => row.startsWith('csrftoken='))
|
|
|
|
?.split('=')[1];
|
|
|
|
if (token) {
|
|
|
|
config.headers['x-csrftoken'] = token;
|
|
|
|
}
|
|
|
|
return config;
|
|
|
|
});
|
2024-07-24 23:20:45 +03:00
|
|
|
|
|
|
|
// ================ Data transfer types ================
|
|
|
|
export type DataCallback<ResponseData = undefined> = (data: ResponseData) => void;
|
|
|
|
|
|
|
|
export interface IFrontRequest<RequestData, ResponseData> {
|
|
|
|
data?: RequestData;
|
2025-01-28 19:45:31 +03:00
|
|
|
successMessage?: string | ((data: ResponseData) => string);
|
2024-07-24 23:20:45 +03:00
|
|
|
}
|
|
|
|
|
2025-01-28 19:45:31 +03:00
|
|
|
export interface IAxiosRequest<RequestData, ResponseData> {
|
|
|
|
endpoint: string;
|
|
|
|
request?: IFrontRequest<RequestData, ResponseData>;
|
|
|
|
options?: AxiosRequestConfig;
|
2025-02-17 14:31:17 +03:00
|
|
|
schema?: z.ZodType;
|
2024-07-24 23:20:45 +03:00
|
|
|
}
|
|
|
|
|
2025-01-28 19:45:31 +03:00
|
|
|
export interface IAxiosGetRequest {
|
2024-07-24 23:20:45 +03:00
|
|
|
endpoint: string;
|
|
|
|
options?: AxiosRequestConfig;
|
2025-01-28 19:45:31 +03:00
|
|
|
signal?: AbortSignal;
|
2025-02-17 14:31:17 +03:00
|
|
|
schema?: z.ZodType;
|
2024-07-24 23:20:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// ================ Transport API calls ================
|
2025-02-17 14:31:17 +03:00
|
|
|
export function axiosGet<ResponseData>({ endpoint, options, schema }: IAxiosGetRequest) {
|
2025-01-28 19:45:31 +03:00
|
|
|
return axiosInstance
|
2024-07-24 23:20:45 +03:00
|
|
|
.get<ResponseData>(endpoint, options)
|
2025-02-17 14:31:17 +03:00
|
|
|
.then(response => {
|
|
|
|
schema?.parse(response.data);
|
|
|
|
return response.data;
|
|
|
|
})
|
2024-07-24 23:20:45 +03:00
|
|
|
.catch((error: Error | AxiosError) => {
|
2025-02-17 14:31:17 +03:00
|
|
|
// Note: Ignore cancellation errors
|
2025-02-04 23:54:24 +03:00
|
|
|
if (error.name !== 'CanceledError') {
|
2025-02-17 14:31:17 +03:00
|
|
|
if (error instanceof ZodError) {
|
|
|
|
toast.error(errorMsg.invalidResponse);
|
|
|
|
} else {
|
|
|
|
toast.error(extractErrorMessage(error));
|
|
|
|
}
|
2025-02-04 23:54:24 +03:00
|
|
|
console.error(error);
|
|
|
|
}
|
2025-01-28 19:45:31 +03:00
|
|
|
throw error;
|
2024-07-24 23:20:45 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-01-28 19:45:31 +03:00
|
|
|
export function axiosPost<RequestData, ResponseData = void>({
|
2024-07-24 23:20:45 +03:00
|
|
|
endpoint,
|
|
|
|
request,
|
2025-02-17 14:31:17 +03:00
|
|
|
options,
|
|
|
|
schema
|
2024-07-24 23:20:45 +03:00
|
|
|
}: IAxiosRequest<RequestData, ResponseData>) {
|
2025-01-28 19:45:31 +03:00
|
|
|
return axiosInstance
|
|
|
|
.post<ResponseData>(endpoint, request?.data, options)
|
2024-07-24 23:20:45 +03:00
|
|
|
.then(response => {
|
2025-02-17 14:31:17 +03:00
|
|
|
schema?.parse(response.data);
|
2025-01-28 19:45:31 +03:00
|
|
|
if (request?.successMessage) {
|
|
|
|
if (typeof request.successMessage === 'string') {
|
|
|
|
toast.success(request.successMessage);
|
|
|
|
} else {
|
|
|
|
toast.success(request.successMessage(response.data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return response.data;
|
2024-07-24 23:20:45 +03:00
|
|
|
})
|
2025-02-17 14:31:17 +03:00
|
|
|
.catch((error: Error | AxiosError | ZodError) => {
|
|
|
|
if (error instanceof ZodError) {
|
|
|
|
toast.error(errorMsg.invalidResponse);
|
|
|
|
} else {
|
|
|
|
toast.error(extractErrorMessage(error));
|
|
|
|
}
|
2025-01-28 19:45:31 +03:00
|
|
|
throw error;
|
2024-07-24 23:20:45 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-01-28 19:45:31 +03:00
|
|
|
export function axiosDelete<RequestData, ResponseData = void>({
|
2024-07-24 23:20:45 +03:00
|
|
|
endpoint,
|
|
|
|
request,
|
2025-02-17 14:31:17 +03:00
|
|
|
options,
|
|
|
|
schema
|
2024-07-24 23:20:45 +03:00
|
|
|
}: IAxiosRequest<RequestData, ResponseData>) {
|
2025-01-28 19:45:31 +03:00
|
|
|
return axiosInstance
|
2024-07-24 23:20:45 +03:00
|
|
|
.delete<ResponseData>(endpoint, options)
|
|
|
|
.then(response => {
|
2025-02-17 14:31:17 +03:00
|
|
|
schema?.parse(response.data);
|
2025-01-28 19:45:31 +03:00
|
|
|
if (request?.successMessage) {
|
|
|
|
if (typeof request.successMessage === 'string') {
|
|
|
|
toast.success(request.successMessage);
|
|
|
|
} else {
|
|
|
|
toast.success(request.successMessage(response.data));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return response.data;
|
2024-07-24 23:20:45 +03:00
|
|
|
})
|
2025-02-17 14:31:17 +03:00
|
|
|
.catch((error: Error | AxiosError | ZodError) => {
|
|
|
|
if (error instanceof ZodError) {
|
|
|
|
toast.error(errorMsg.invalidResponse);
|
|
|
|
} else {
|
|
|
|
toast.error(extractErrorMessage(error));
|
|
|
|
}
|
2025-01-28 19:45:31 +03:00
|
|
|
throw error;
|
2024-07-24 23:20:45 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-01-28 19:45:31 +03:00
|
|
|
export function axiosPatch<RequestData, ResponseData = void>({
|
2024-07-24 23:20:45 +03:00
|
|
|
endpoint,
|
|
|
|
request,
|
2025-02-17 14:31:17 +03:00
|
|
|
options,
|
|
|
|
schema
|
2024-07-24 23:20:45 +03:00
|
|
|
}: IAxiosRequest<RequestData, ResponseData>) {
|
2025-01-28 19:45:31 +03:00
|
|
|
return axiosInstance
|
|
|
|
.patch<ResponseData>(endpoint, request?.data, options)
|
2024-07-24 23:20:45 +03:00
|
|
|
.then(response => {
|
2025-02-17 14:31:17 +03:00
|
|
|
schema?.parse(response.data);
|
2025-01-28 19:45:31 +03:00
|
|
|
if (request?.successMessage) {
|
|
|
|
if (typeof request.successMessage === 'string') {
|
|
|
|
toast.success(request.successMessage);
|
|
|
|
} else {
|
|
|
|
toast.success(request.successMessage(response.data));
|
|
|
|
}
|
|
|
|
}
|
2024-07-24 23:20:45 +03:00
|
|
|
return response.data;
|
|
|
|
})
|
2025-02-17 14:31:17 +03:00
|
|
|
.catch((error: Error | AxiosError | ZodError) => {
|
|
|
|
if (error instanceof ZodError) {
|
|
|
|
toast.error(errorMsg.invalidResponse);
|
|
|
|
} else {
|
|
|
|
toast.error(extractErrorMessage(error));
|
|
|
|
}
|
2025-01-28 19:45:31 +03:00
|
|
|
throw error;
|
2024-07-24 23:20:45 +03:00
|
|
|
});
|
|
|
|
}
|