import { defineBoot } from "#q-app/wrappers"; import { Cookies, Notify } from "quasar"; import axios from "axios"; import { userStore } from "src/stores/user"; const api = axios.create({ baseURL: process.env.API_URL + "/api", withCredentials: true, }); api.interceptors.request.use( async (config) => { const accessToken = userStore().accessToken; const savedLanguage = Cookies.get("locale"); const language = savedLanguage || window.navigator.language; config.headers["Accept-Language"] = language; config.headers["X-App-Origin"] = process.env.APP_NAME; if (accessToken) { config.headers.Authorization = `Bearer ${accessToken}`; } return config; }, (error) => { return Promise.reject(error); }, ); let isRefreshing = false; let failedQueue = []; const processQueue = (error, token = null) => { failedQueue.forEach((prom) => { if (error) { prom.reject(error); } else { prom.config.headers["Authorization"] = "Bearer " + token; prom.resolve(api(prom.config)); } }); failedQueue = []; }; const errorInterceptor = async (error, router) => { const originalRequest = error.config; const user_store = userStore(); if (error.response?.status === 422) { return Promise.reject(error); } if ( error.response?.status !== 401 || originalRequest.url.includes("/refresh") ) { if (error?.response?.data?.message) { Notify.create({ message: error?.response?.data?.message, type: "negative", }); } return Promise.reject(error); } if (error?.config?.url === "/login") { if (error?.response?.data?.message) { Notify.create({ message: error?.response?.data?.message, type: "negative", }); } return Promise.reject(error); } if (isRefreshing) { return new Promise((resolve, reject) => { failedQueue.push({ resolve, reject, config: originalRequest }); }); } isRefreshing = true; try { const response = await api.post("/refresh"); const newAccessToken = response.data.payload.access_token; user_store.accessToken = newAccessToken; originalRequest.headers["Authorization"] = `Bearer ${newAccessToken}`; processQueue(null, newAccessToken); return api(originalRequest); } catch (err) { processQueue(err, null); user_store.resetUser(); router.push("/login"); return Promise.reject(err); } finally { isRefreshing = false; } }; const successInterceptor = (response) => { if (response?.data?.message) { Notify.create({ message: response?.data?.message, type: "positive", }); } return response; }; export default defineBoot(({ app, router }) => { api.interceptors.response.use( (response) => successInterceptor(response), (error) => errorInterceptor(error, router), ); // for use inside Vue files (Options API) through this.$axios and this.$api app.config.globalProperties.$axios = axios; // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form) // so you won't necessarily have to import axios in each vue file app.config.globalProperties.$api = api; // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form) // so you can easily perform requests against your app's API }); export { api };