⚡️(frontend) prevent authentication retry on 401 responses
Stop retry attempts when receiving 401 Unauthorized from /me endpoint since this clearly indicates authentication status. The original purpose of the /me call is simply to determine if user is authenticated, and a 401 provides sufficient information. Prevents unnecessary network requests caused by React Query's automatic retry behavior when re-raising exceptions, which was hiding the 401 status. Improves performance and reduces server load during authentication failures.
This commit is contained in:
committed by
Anthony LC
parent
ff8275fb4e
commit
2a7ffff96d
@@ -9,6 +9,8 @@ import { useResponsiveStore } from '@/stores/';
|
|||||||
|
|
||||||
import { ConfigProvider } from './config/';
|
import { ConfigProvider } from './config/';
|
||||||
|
|
||||||
|
export const DEFAULT_QUERY_RETRY = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* QueryClient:
|
* QueryClient:
|
||||||
* - defaultOptions:
|
* - defaultOptions:
|
||||||
@@ -19,7 +21,7 @@ import { ConfigProvider } from './config/';
|
|||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
queries: {
|
queries: {
|
||||||
staleTime: 1000 * 60 * 3,
|
staleTime: 1000 * 60 * 3,
|
||||||
retry: 1,
|
retry: DEFAULT_QUERY_RETRY,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import { UseQueryOptions, useQuery } from '@tanstack/react-query';
|
import { UseQueryOptions, useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||||
|
import { DEFAULT_QUERY_RETRY } from '@/core';
|
||||||
|
|
||||||
import { User } from './types';
|
import { User } from './types';
|
||||||
|
|
||||||
|
type UserResponse = User | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously retrieves the current user's data from the API.
|
* Asynchronously retrieves the current user's data from the API.
|
||||||
* This function is called during frontend initialization to check
|
* This function is called during frontend initialization to check
|
||||||
@@ -14,8 +17,13 @@ import { User } from './types';
|
|||||||
* @throws {Error} Throws an error if the API request fails.
|
* @throws {Error} Throws an error if the API request fails.
|
||||||
* @returns {Promise<User>} A promise that resolves to the user data.
|
* @returns {Promise<User>} A promise that resolves to the user data.
|
||||||
*/
|
*/
|
||||||
export const getMe = async (): Promise<User> => {
|
export const getMe = async (): Promise<UserResponse> => {
|
||||||
const response = await fetchAPI(`users/me/`);
|
const response = await fetchAPI(`users/me/`);
|
||||||
|
|
||||||
|
if (response.status === 401) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new APIError(
|
throw new APIError(
|
||||||
`Couldn't fetch user data: ${response.statusText}`,
|
`Couldn't fetch user data: ${response.statusText}`,
|
||||||
@@ -28,12 +36,19 @@ export const getMe = async (): Promise<User> => {
|
|||||||
export const KEY_AUTH = 'auth';
|
export const KEY_AUTH = 'auth';
|
||||||
|
|
||||||
export function useAuthQuery(
|
export function useAuthQuery(
|
||||||
queryConfig?: UseQueryOptions<User, APIError, User>,
|
queryConfig?: UseQueryOptions<UserResponse, APIError, UserResponse>,
|
||||||
) {
|
) {
|
||||||
return useQuery<User, APIError, User>({
|
return useQuery<UserResponse, APIError, UserResponse>({
|
||||||
queryKey: [KEY_AUTH],
|
queryKey: [KEY_AUTH],
|
||||||
queryFn: getMe,
|
queryFn: getMe,
|
||||||
staleTime: 1000 * 60 * 15, // 15 minutes
|
staleTime: 1000 * 60 * 15, // 15 minutes
|
||||||
|
retry: (failureCount, error) => {
|
||||||
|
// we assume that a 401 means the user is not logged in
|
||||||
|
if (error.status == 401) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return failureCount < DEFAULT_QUERY_RETRY;
|
||||||
|
},
|
||||||
...queryConfig,
|
...queryConfig,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export const useSynchronizedLanguage = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const changeBackendLanguage = useCallback(
|
const changeBackendLanguage = useCallback(
|
||||||
async (language: string, user?: User) => {
|
async (language: string, user?: User | null) => {
|
||||||
const closestBackendLanguage = getMatchingLocales(
|
const closestBackendLanguage = getMatchingLocales(
|
||||||
availableBackendLanguages,
|
availableBackendLanguages,
|
||||||
[language],
|
[language],
|
||||||
@@ -52,7 +52,7 @@ export const useSynchronizedLanguage = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const changeLanguageSynchronized = useCallback(
|
const changeLanguageSynchronized = useCallback(
|
||||||
async (language: string, user?: User) => {
|
async (language: string, user?: User | null) => {
|
||||||
if (!isSynchronizingLanguage.current) {
|
if (!isSynchronizingLanguage.current) {
|
||||||
isSynchronizingLanguage.current = true;
|
isSynchronizingLanguage.current = true;
|
||||||
await changeFrontendLanguage(language);
|
await changeFrontendLanguage(language);
|
||||||
|
|||||||
Reference in New Issue
Block a user