axios.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import { boot } from "quasar/wrappers";
  2. import { useAuth } from "src/composables/useAuth";
  3. import { Cookies, Notify } from "quasar";
  4. import axios from "axios";
  5. const api = axios.create({
  6. baseURL: process.env.API_URL + "/api",
  7. withCredentials: true,
  8. withXSRFToken: true,
  9. });
  10. api.interceptors.request.use(
  11. async (config) => {
  12. const accessToken = Cookies.get("access_token");
  13. const savedLanguage = Cookies.get("locale");
  14. const language = savedLanguage || window.navigator.language;
  15. config.headers["Accept-Language"] = language;
  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 validQueue = [];
  27. const errorInterceptor = async (error) => {
  28. if (error.config?.retryCount) {
  29. error.config.retryCount = 0;
  30. }
  31. if (error.config.retryCount >= 3) {
  32. return Promise.reject(error);
  33. }
  34. error.config.retryCount++;
  35. if (!error.response) {
  36. Notify.create({
  37. message: error.message,
  38. type: "negative",
  39. });
  40. return Promise.reject(error);
  41. }
  42. if (error.response.status === 401) {
  43. if (error?.config?.url === "/login") {
  44. Notify.create({
  45. message: error.response.data.message,
  46. type: "negative",
  47. });
  48. return Promise.reject(error);
  49. }
  50. if (isRefreshing) {
  51. return new Promise((resolve, reject) => {
  52. validQueue.push({ resolve, reject, config: error.config });
  53. });
  54. }
  55. isRefreshing = true;
  56. try {
  57. await useAuth().refreshToken();
  58. } catch (error) {
  59. validQueue = [];
  60. Cookies.remove("access_token");
  61. Cookies.remove("refresh_token");
  62. if (window.location.pathname !== "/login") {
  63. window.location.href = "/login";
  64. }
  65. return Promise.reject(error);
  66. }
  67. try {
  68. validQueue.forEach((request) => {
  69. request.resolve(api.request(request.config));
  70. });
  71. validQueue = [];
  72. return await api.request(error.config);
  73. } catch (error) {
  74. Notify.create({
  75. message: error.response.data.message,
  76. type: "negative",
  77. });
  78. } finally {
  79. isRefreshing = false;
  80. }
  81. }
  82. Notify.create({
  83. message: error.response.data.message,
  84. type: "negative",
  85. });
  86. return Promise.reject(error);
  87. };
  88. const successInterceptor = (response) => {
  89. if (response.data.message) {
  90. Notify.create({
  91. message: response.data.message,
  92. type: "positive",
  93. });
  94. }
  95. return response;
  96. };
  97. export default boot(({ app }) => {
  98. api.interceptors.response.use(
  99. (response) => successInterceptor(response),
  100. (error) => errorInterceptor(error),
  101. );
  102. // for use inside Vue files (Options API) through this.$axios and this.$api
  103. app.config.globalProperties.$axios = axios;
  104. // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
  105. // so you won't necessarily have to import axios in each vue file
  106. app.config.globalProperties.$api = api;
  107. // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
  108. // so you can easily perform requests against your app's API
  109. });
  110. export { api };