flaschengeist-frontend/src/boot/axios.ts

109 lines
3.3 KiB
TypeScript

/**
* This boot file registers interceptors for axios
*/
import { useMainStore, api } from '@flaschengeist/api';
import { AxiosError } from 'axios';
import { boot } from 'quasar/wrappers';
import config from 'src/config';
import { clone } from '@flaschengeist/api';
/**
* Minify data sent to backend server
*
* Drop unneeded entities which can be identified by ID.
*
* @param obj Object to minify
* @param cloned If this entity is already cloned (JSON En+Decoded)
* @returns Minified object (some types are converted, like a Date object is now a ISO string)
*/
function minify(entity: unknown, cloned = false) {
if (!cloned) entity = clone(entity);
if (typeof entity === 'object') {
const obj = entity as { [index: string]: unknown };
for (const prop in obj) {
if (obj.hasOwnProperty(prop) && !!obj[prop]) {
if (Array.isArray(obj[prop])) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
obj[prop] = (<Array<unknown>>obj[prop]).map((v) => minify(v, true));
} else if (
typeof obj[prop] === 'object' &&
Object.keys(<object>obj[prop]).includes('id') &&
typeof (<{ id: unknown }>obj[prop])['id'] === 'number' &&
!isNaN((<{ id: number }>obj[prop])['id'])
) {
obj[prop] = (<{ id: unknown }>obj[prop])['id'];
}
}
}
return obj;
}
return entity;
}
export default boot(({ router }) => {
// Persisted value is read in plugins.ts boot file!
if (api.defaults.baseURL === undefined) api.defaults.baseURL = config.baseURL;
/***
* Intercept requests
* - insert Token if available
* - minify JSON requests
*/
api.interceptors.request.use((config) => {
const store = useMainStore();
if (store.session?.token) {
config.headers = { Authorization: 'Bearer ' + store.session.token };
}
// Minify JSON requests
if (
!!config.data &&
(config.headers === undefined ||
config.headers['Content-Type'] === undefined ||
config.headers['Content-Type'] === 'application/json')
)
config.data = minify(config.data);
return config;
});
/***
* Intercept responses
* - filter 401 --> handleLoggedOut
* - filter timeout or 502-504 --> backendOffline
*/
api.interceptors.response.use(
(response) => response,
async (error) => {
const store = useMainStore();
if (error) {
const e = <AxiosError>error;
const current = router.currentRoute.value;
if (
e.code === 'ECONNABORTED' ||
(e.response && e.response.status >= 502 && e.response.status <= 504)
) {
let next = current.path;
if ((current.name == 'login' || current.name == 'offline') && current.query.redirect)
next = <string>current.query.redirect;
await router.push({
name: 'offline',
query: { redirect: next },
});
} else if (e.response && e.response.status == 401) {
void store.handleLoggedOut();
if (current.name !== 'login') {
await router.push({
name: 'login',
params: { logout: 'logout' },
query: { redirect: current.path },
});
}
}
}
throw error;
}
);
});