axios.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import { defineBoot } from "#q-app/wrappers";
  2. import { Cookies, Notify } from "quasar";
  3. import axios from "axios";
  4. import { useRouter } from "vue-router";
  5. import { useAuth } from "src/composables/useAuth";
  6. import { userStore } from "src/stores/user";
  7. const api = axios.create({
  8. baseURL: process.env.API_URL + "/api",
  9. withCredentials: true,
  10. });
  11. api.interceptors.request.use(
  12. async (config) => {
  13. const accessToken = userStore().accessToken;
  14. const savedLanguage = Cookies.get("locale");
  15. const language = savedLanguage || window.navigator.language;
  16. config.headers["Accept-Language"] = language;
  17. if (accessToken) {
  18. config.headers.Authorization = `Bearer ${accessToken}`;
  19. }
  20. return config;
  21. },
  22. (error) => {
  23. return Promise.reject(error);
  24. },
  25. );
  26. let isRefreshing = false;
  27. let failedQueue = [];
  28. const processQueue = (error, token = null) => {
  29. failedQueue.forEach((prom) => {
  30. if (error) {
  31. prom.reject(error);
  32. } else {
  33. prom.config.headers["Authorization"] = "Bearer " + token;
  34. prom.resolve(api(prom.config));
  35. }
  36. });
  37. failedQueue = [];
  38. };
  39. const errorInterceptor = async (error, router) => {
  40. const originalRequest = error.config;
  41. const user_store = userStore();
  42. if (error.response?.status === 422) {
  43. if (error.response?.data?.error === "missing_payment_data") {
  44. Notify.create({
  45. message: error.response.data.message,
  46. type: "negative",
  47. });
  48. router.push({ name: "ProfilePage" });
  49. }
  50. return Promise.reject(error);
  51. }
  52. if (
  53. error.response?.status !== 401 ||
  54. originalRequest.url.includes("/refresh")
  55. ) {
  56. Notify.create({
  57. message: error?.response?.data?.message ?? error.message,
  58. type: "negative",
  59. });
  60. return Promise.reject(error);
  61. }
  62. if (error?.config?.url === "/login") {
  63. Notify.create({
  64. message: error.response.data.message,
  65. type: "negative",
  66. });
  67. return Promise.reject(error);
  68. }
  69. if (isRefreshing) {
  70. return new Promise((resolve, reject) => {
  71. failedQueue.push({ resolve, reject, config: originalRequest });
  72. });
  73. }
  74. isRefreshing = true;
  75. try {
  76. const response = await useAuth().refresh();
  77. const newAccessToken = response.data.payload.access_token;
  78. user_store.accessToken = newAccessToken;
  79. originalRequest.headers["Authorization"] = `Bearer ${newAccessToken}`;
  80. processQueue(null, newAccessToken);
  81. return api(originalRequest);
  82. } catch (err) {
  83. processQueue(err, null);
  84. await useAuth().clearAuthData();
  85. router.push("/login");
  86. return Promise.reject(err);
  87. } finally {
  88. isRefreshing = false;
  89. }
  90. };
  91. const successInterceptor = (response) => {
  92. if (response.data.message) {
  93. Notify.create({
  94. message: response.data.message,
  95. type: "positive",
  96. });
  97. }
  98. return response;
  99. };
  100. export default defineBoot(({ app }) => {
  101. const router = useRouter();
  102. api.interceptors.response.use(
  103. (response) => successInterceptor(response),
  104. (error) => errorInterceptor(error, router),
  105. );
  106. // for use inside Vue files (Options API) through this.$axios and this.$api
  107. app.config.globalProperties.$axios = axios;
  108. // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
  109. // so you won't necessarily have to import axios in each vue file
  110. app.config.globalProperties.$api = api;
  111. // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
  112. // so you can easily perform requests against your app's API
  113. });
  114. export { api };