Client - cancel duplicate api calls
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
			
		||||
import axios from 'axios'
 | 
			
		||||
 | 
			
		||||
import { pendingRequests, removeRequestIfPending } from '@/api/pending'
 | 
			
		||||
import store from '@/store'
 | 
			
		||||
import { AUTH_USER_STORE } from '@/store/constants'
 | 
			
		||||
import { getApiUrl } from '@/utils'
 | 
			
		||||
@@ -10,6 +11,11 @@ const authApi = axios.create({
 | 
			
		||||
 | 
			
		||||
authApi.interceptors.request.use(
 | 
			
		||||
  (config) => {
 | 
			
		||||
    const controller = new AbortController()
 | 
			
		||||
    config.signal = controller.signal
 | 
			
		||||
    const requestKey = removeRequestIfPending(config)
 | 
			
		||||
    pendingRequests.set(requestKey, controller)
 | 
			
		||||
 | 
			
		||||
    const authToken = store.getters[AUTH_USER_STORE.GETTERS.AUTH_TOKEN]
 | 
			
		||||
    if (authToken) {
 | 
			
		||||
      const auth = `Bearer ${authToken}`
 | 
			
		||||
@@ -22,4 +28,17 @@ authApi.interceptors.request.use(
 | 
			
		||||
  (error) => Promise.reject(error)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
authApi.interceptors.response.use(
 | 
			
		||||
  (response) => {
 | 
			
		||||
    removeRequestIfPending(response.config)
 | 
			
		||||
    return response
 | 
			
		||||
  },
 | 
			
		||||
  (error) => {
 | 
			
		||||
    if (error.message !== 'canceled') {
 | 
			
		||||
      removeRequestIfPending(error.response.config)
 | 
			
		||||
    }
 | 
			
		||||
    return Promise.reject(error)
 | 
			
		||||
  }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export default authApi
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,34 @@
 | 
			
		||||
import axios from 'axios'
 | 
			
		||||
 | 
			
		||||
import { pendingRequests, removeRequestIfPending } from '@/api/pending'
 | 
			
		||||
import { getApiUrl } from '@/utils'
 | 
			
		||||
 | 
			
		||||
const api = axios.create({
 | 
			
		||||
  baseURL: getApiUrl(),
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
api.interceptors.request.use(
 | 
			
		||||
  (config) => {
 | 
			
		||||
    const controller = new AbortController()
 | 
			
		||||
    config.signal = controller.signal
 | 
			
		||||
    const requestKey = removeRequestIfPending(config)
 | 
			
		||||
    pendingRequests.set(requestKey, controller)
 | 
			
		||||
    return config
 | 
			
		||||
  },
 | 
			
		||||
  (error) => Promise.reject(error)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
api.interceptors.response.use(
 | 
			
		||||
  (response) => {
 | 
			
		||||
    removeRequestIfPending(response.config)
 | 
			
		||||
    return response
 | 
			
		||||
  },
 | 
			
		||||
  (error) => {
 | 
			
		||||
    if (error.message !== 'canceled') {
 | 
			
		||||
      removeRequestIfPending(error.response.config)
 | 
			
		||||
    }
 | 
			
		||||
    return Promise.reject(error)
 | 
			
		||||
  }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
export default api
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								fittrackee_client/src/api/pending.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								fittrackee_client/src/api/pending.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
import { AxiosRequestConfig } from 'axios'
 | 
			
		||||
 | 
			
		||||
export const pendingRequests = new Map()
 | 
			
		||||
 | 
			
		||||
const generateRequestKey = (config: AxiosRequestConfig): string => {
 | 
			
		||||
  const { method, url, params = {}, data = {} } = config
 | 
			
		||||
  return [method, url, JSON.stringify(params), JSON.stringify(data)].join('')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const removeRequestIfPending = (config: AxiosRequestConfig): string => {
 | 
			
		||||
  const requestKey = generateRequestKey(config)
 | 
			
		||||
  if (pendingRequests.has(requestKey)) {
 | 
			
		||||
    const controller = pendingRequests.get(requestKey) || {}
 | 
			
		||||
    controller?.abort()
 | 
			
		||||
    pendingRequests.delete(requestKey)
 | 
			
		||||
  }
 | 
			
		||||
  return requestKey
 | 
			
		||||
}
 | 
			
		||||
@@ -142,8 +142,10 @@ export const actions: ActionTree<IAuthUserState, IRootState> &
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      .catch((error) => {
 | 
			
		||||
        handleError(context, error)
 | 
			
		||||
        removeAuthUserData(context)
 | 
			
		||||
        if (error.message !== 'canceled') {
 | 
			
		||||
          handleError(context, error)
 | 
			
		||||
          removeAuthUserData(context)
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
  },
 | 
			
		||||
  [AUTH_USER_STORE.ACTIONS.LOGIN_OR_REGISTER](
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,12 @@ export const handleError = (
 | 
			
		||||
  error: AxiosError | null,
 | 
			
		||||
  msg = 'UNKNOWN'
 | 
			
		||||
): void => {
 | 
			
		||||
  // if stored token is blacklisted
 | 
			
		||||
  // if request is cancelled, no error to display
 | 
			
		||||
  if (error && error.message === 'canceled') {
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // if stored token is blacklisted, disconnect user
 | 
			
		||||
  if (
 | 
			
		||||
    error?.response?.status === 401 &&
 | 
			
		||||
    error.response.data.error === 'invalid_token'
 | 
			
		||||
@@ -37,6 +42,7 @@ export const handleError = (
 | 
			
		||||
    context.dispatch(AUTH_USER_STORE.ACTIONS.CHECK_AUTH_USER)
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const errorMessages = !error
 | 
			
		||||
    ? msg
 | 
			
		||||
    : error.response
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user