From a040b0c8459c3baa7e363edb7ac2ac657080fb8b Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 19 Sep 2022 10:53:31 +0200 Subject: [PATCH] Client - cancel duplicate api calls --- fittrackee_client/src/api/authApi.ts | 19 ++++++++++++++ fittrackee_client/src/api/defaultApi.ts | 25 +++++++++++++++++++ fittrackee_client/src/api/pending.ts | 18 +++++++++++++ .../src/store/modules/authUser/actions.ts | 6 +++-- fittrackee_client/src/utils/index.ts | 8 +++++- 5 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 fittrackee_client/src/api/pending.ts diff --git a/fittrackee_client/src/api/authApi.ts b/fittrackee_client/src/api/authApi.ts index 1f7de003..6ea4ca5e 100644 --- a/fittrackee_client/src/api/authApi.ts +++ b/fittrackee_client/src/api/authApi.ts @@ -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 diff --git a/fittrackee_client/src/api/defaultApi.ts b/fittrackee_client/src/api/defaultApi.ts index 31a2474c..791658dc 100644 --- a/fittrackee_client/src/api/defaultApi.ts +++ b/fittrackee_client/src/api/defaultApi.ts @@ -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 diff --git a/fittrackee_client/src/api/pending.ts b/fittrackee_client/src/api/pending.ts new file mode 100644 index 00000000..6f20ed98 --- /dev/null +++ b/fittrackee_client/src/api/pending.ts @@ -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 +} diff --git a/fittrackee_client/src/store/modules/authUser/actions.ts b/fittrackee_client/src/store/modules/authUser/actions.ts index 25a41e00..144127c4 100644 --- a/fittrackee_client/src/store/modules/authUser/actions.ts +++ b/fittrackee_client/src/store/modules/authUser/actions.ts @@ -142,8 +142,10 @@ export const actions: ActionTree & } }) .catch((error) => { - handleError(context, error) - removeAuthUserData(context) + if (error.message !== 'canceled') { + handleError(context, error) + removeAuthUserData(context) + } }) }, [AUTH_USER_STORE.ACTIONS.LOGIN_OR_REGISTER]( diff --git a/fittrackee_client/src/utils/index.ts b/fittrackee_client/src/utils/index.ts index 0cc2c51f..fbaabd4a 100644 --- a/fittrackee_client/src/utils/index.ts +++ b/fittrackee_client/src/utils/index.ts @@ -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