axios.js 3.3 KB

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