1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-25 08:19:40 +02:00
portainer/app/portainer/services/axios.ts
2023-11-20 09:35:03 +02:00

134 lines
3.3 KiB
TypeScript

import axiosOrigin, { AxiosError, AxiosRequestConfig } from 'axios';
import { loadProgressBar } from 'axios-progress-bar';
import 'axios-progress-bar/dist/nprogress.css';
import PortainerError from '@/portainer/error';
import {
portainerAgentManagerOperation,
portainerAgentTargetHeader,
} from './http-request.helper';
const axios = axiosOrigin.create({ baseURL: 'api' });
loadProgressBar(undefined, axios);
export default axios;
export const agentTargetHeader = 'X-PortainerAgent-Target';
export function agentInterceptor(config: AxiosRequestConfig) {
if (!config.url || !config.url.includes('/docker/')) {
return config;
}
const newConfig = { headers: config.headers || {}, ...config };
const target = portainerAgentTargetHeader();
if (target) {
newConfig.headers[agentTargetHeader] = target;
}
if (portainerAgentManagerOperation()) {
newConfig.headers['X-PortainerAgent-ManagerOperation'] = '1';
}
return newConfig;
}
axios.interceptors.request.use(agentInterceptor);
axios.interceptors.response.use(undefined, (error) => {
if (
error.response?.status === 401 &&
!error.config.url.includes('/v2/') &&
!error.config.url.includes('/api/v4/') &&
isTransitionRequiresAuthentication()
) {
// eslint-disable-next-line no-console
console.error('Unauthorized request, logging out');
window.location.hash = '/logout';
window.location.reload();
}
return Promise.reject(error);
});
const UNAUTHENTICATED_ROUTES = [
'/logout',
'/internal-auth',
'/auth',
'/init/admin',
];
function isTransitionRequiresAuthentication() {
return !UNAUTHENTICATED_ROUTES.some((route) =>
window.location.hash.includes(route)
);
}
/**
* Parses an Axios error and returns a PortainerError.
* @param err The original error.
* @param msg An optional error message to prepend.
* @param parseError A function to parse AxiosErrors. Defaults to defaultErrorParser.
* @returns A PortainerError with the parsed error message and details.
*/
export function parseAxiosError(
err: unknown,
msg = '',
parseError = defaultErrorParser
) {
let resultErr = err;
let resultMsg = msg;
if (isAxiosError(err)) {
const { error, details } = parseError(err);
resultErr = error;
if (msg && details) {
resultMsg = `${msg}: ${details}`;
} else {
resultMsg = msg || details;
}
}
return new PortainerError(resultMsg, resultErr);
}
export function defaultErrorParser(axiosError: AxiosError) {
const message = axiosError.response?.data.message || '';
const details = axiosError.response?.data.details || message;
const error = new Error(message);
return { error, details };
}
export function isAxiosError<
ResponseType = { message: string; details: string },
>(error: unknown): error is AxiosError<ResponseType> {
return axiosOrigin.isAxiosError(error);
}
export function arrayToJson<T>(arr?: Array<T>) {
if (!arr) {
return '';
}
return JSON.stringify(arr);
}
export function json2formData(json: Record<string, unknown>) {
const formData = new FormData();
Object.entries(json).forEach(([key, value]) => {
if (typeof value === 'undefined' || value === null) {
return;
}
if (Array.isArray(value)) {
formData.append(key, arrayToJson(value));
return;
}
formData.append(key, value as string);
});
return formData;
}