From 7ca9df7f9df79a8b994390056bf18173bba819e3 Mon Sep 17 00:00:00 2001 From: Bassel Kanso Date: Mon, 8 Apr 2024 21:43:37 +0300 Subject: [PATCH] chore: error handling for fetch --- .../admin/src/hooks/useAPIErrorHandler.ts | 16 ++++---- .../pages/Settings/pages/Roles/ListPage.tsx | 4 +- .../core/admin/admin/src/utils/baseQuery.ts | 33 +++++++++------- .../admin/admin/src/utils/getFetchClient.ts | 34 ++++++++-------- .../admin/src/utils/normalizeAPIError.ts | 4 +- .../src/utils/tests/getFetchClient.test.ts | 4 +- .../content-manager/admin/src/utils/api.ts | 8 ++-- .../src/components/CMReleasesContainer.tsx | 3 +- .../admin/src/components/ReleaseAction.tsx | 4 +- .../src/components/ReleaseActionMenu.tsx | 11 ++++-- .../admin/src/pages/ReleaseDetailsPage.tsx | 12 +++--- .../admin/src/pages/ReleasesPage.tsx | 4 +- .../admin/src/services/baseQuery.ts | 39 ++++++------------- .../admin/src/services/api.ts | 4 +- .../review-workflows/admin/src/utils/api.ts | 23 +++++------ .../documentation/admin/src/services/api.ts | 4 +- .../admin/src/utils/baseQuery.ts | 23 +++++------ .../plugins/i18n/admin/src/services/api.ts | 4 +- .../plugins/i18n/admin/src/utils/baseQuery.ts | 23 +++++------ 19 files changed, 127 insertions(+), 130 deletions(-) diff --git a/packages/core/admin/admin/src/hooks/useAPIErrorHandler.ts b/packages/core/admin/admin/src/hooks/useAPIErrorHandler.ts index 7ee2d65643..013067981b 100644 --- a/packages/core/admin/admin/src/hooks/useAPIErrorHandler.ts +++ b/packages/core/admin/admin/src/hooks/useAPIErrorHandler.ts @@ -1,6 +1,5 @@ import * as React from 'react'; -import { AxiosError } from 'axios'; import { IntlFormatters, useIntl } from 'react-intl'; import { FetchError } from '../utils/getFetchClient'; @@ -121,18 +120,18 @@ export function useAPIErrorHandler( /** * @description This method try to normalize the passed error * and then call formatAPIError to stringify the ResponseObject - * into a string. If it fails it will call formatAxiosError and + * into a string. If it fails it will call formatFetchError and * return the error message. */ const formatError = React.useCallback( - (error: AxiosError<{ error: ApiError }>) => { + (error: FetchError) => { // Try to normalize the passed error first. This will fail for e.g. network // errors which are thrown by Axios directly. try { const formattedErr = formatAPIError(error, { intlMessagePrefixCallback, formatMessage }); if (!formattedErr) { - return formatAxiosError(error, { intlMessagePrefixCallback, formatMessage }); + return formatFetchError(error, { intlMessagePrefixCallback, formatMessage }); } return formattedErr; @@ -192,7 +191,7 @@ export function useAPIErrorHandler( error, }, }, - } as AxiosError<{ error: BaseQueryError }>; + } as FetchError; /** * There's a chance with SerializedErrors that the message is not set. @@ -202,7 +201,6 @@ export function useAPIErrorHandler( return 'Unknown error occured.'; } - // @ts-expect-error – UnknownApiError is in the same shape as ApiError, but we don't want to expose this to users yet. return formatError(err); }, [formatError] @@ -211,8 +209,8 @@ export function useAPIErrorHandler( }; } -function formatAxiosError( - error: AxiosError, +function formatFetchError( + error: FetchError, { intlMessagePrefixCallback, formatMessage }: FormatAPIErrorOptions ) { const { code, message } = error; @@ -238,7 +236,7 @@ type FormatAPIErrorOptions = Partial, + error: FetchError, { formatMessage, intlMessagePrefixCallback }: FormatAPIErrorOptions ) { if (!formatMessage) { diff --git a/packages/core/admin/admin/src/pages/Settings/pages/Roles/ListPage.tsx b/packages/core/admin/admin/src/pages/Settings/pages/Roles/ListPage.tsx index 080f1ea6b1..9fed1e9cc5 100644 --- a/packages/core/admin/admin/src/pages/Settings/pages/Roles/ListPage.tsx +++ b/packages/core/admin/admin/src/pages/Settings/pages/Roles/ListPage.tsx @@ -15,7 +15,6 @@ import { VisuallyHidden, } from '@strapi/design-system'; import { Duplicate, Pencil, Plus, Trash } from '@strapi/icons'; -import { AxiosError } from 'axios'; import { produce } from 'immer'; import { useIntl } from 'react-intl'; import { useNavigate } from 'react-router-dom'; @@ -31,6 +30,7 @@ import { useFetchClient } from '../../../../hooks/useFetchClient'; import { useQueryParams } from '../../../../hooks/useQueryParams'; import { useRBAC } from '../../../../hooks/useRBAC'; import { selectAdminPermissions } from '../../../../selectors'; +import { isFetchError } from '../../../../utils/getFetchClient'; import { RoleRow, RoleRowProps } from './components/RoleRow'; @@ -74,7 +74,7 @@ const ListPage = () => { type: 'RESET_DATA_TO_DELETE', }); } catch (error) { - if (error instanceof AxiosError) { + if (isFetchError(error)) { toggleNotification({ type: 'danger', message: formatAPIError(error), diff --git a/packages/core/admin/admin/src/utils/baseQuery.ts b/packages/core/admin/admin/src/utils/baseQuery.ts index 79896006b3..41f0cbb5c2 100644 --- a/packages/core/admin/admin/src/utils/baseQuery.ts +++ b/packages/core/admin/admin/src/utils/baseQuery.ts @@ -5,9 +5,6 @@ import { getFetchClient, isFetchError, type FetchConfig } from '../utils/getFetc import type { ApiError } from '../hooks/useAPIErrorHandler'; -/* ------------------------------------------------------------------------------------------------- - * Axios data - * -----------------------------------------------------------------------------------------------*/ export interface QueryArguments { url: string; method?: string; @@ -73,16 +70,26 @@ const fetchBaseQuery = // Handle error of type FetchError if (isFetchError(err)) { - return { - data: undefined, - error: { - name: 'UnknownError', - message: err.message, - details: err.response, - status: err.response?.status, - stack: err.stack, - } as UnknownApiError, - }; + if ( + typeof err.response?.data === 'object' && + err.response?.data !== null && + 'error' in err.response?.data + ) { + /** + * This will most likely be ApiError + */ + return { data: undefined, error: err.response?.data.error as any }; + } else { + return { + data: undefined, + error: { + name: 'UnknownError', + message: err.message, + details: err.response, + status: err.response?.error.status, + } as UnknownApiError, + }; + } } const error = err as Error; diff --git a/packages/core/admin/admin/src/utils/getFetchClient.ts b/packages/core/admin/admin/src/utils/getFetchClient.ts index 3e1dd86fc4..c1f606f937 100644 --- a/packages/core/admin/admin/src/utils/getFetchClient.ts +++ b/packages/core/admin/admin/src/utils/getFetchClient.ts @@ -1,5 +1,7 @@ import qs from 'qs'; +import type { ApiError } from '../hooks/useAPIErrorHandler'; + const STORAGE_KEYS = { TOKEN: 'jwtToken', USER: 'userInfo', @@ -21,16 +23,23 @@ export type FetchConfig = { fetchConfig?: FetchParams[1]; }; +type ErrorResponse = { + data: any; + error: ApiError & { status: number }; +}; + export class FetchError extends Error { public name: string; public message: string; - public response?: Response; + public response?: ErrorResponse; + public code?: number; - constructor(message: string, response?: Response) { + constructor(message: string, response?: ErrorResponse) { super(message); this.name = 'FetchError'; this.message = message; this.response = response; + this.code = response?.error.status; // Ensure correct stack trace in error object if (Error.captureStackTrace) { @@ -104,7 +113,9 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => { response: Response ): Promise> => { const result = await response.json(); - + if (result.error) { + throw new FetchError(result.error.message, result); + } return { data: result, }; @@ -129,21 +140,12 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => { return `${baseURL}${url}`; }; - const fetchHandler = async (url: string, options?: FetchOptions) => { - const response = await fetch(url, options); - if (!response.ok) { - throw new FetchError(`Failed to fetch data: ${response.statusText}`, response); - } - - return response; - }; - const fetchClient: FetchClient = { get: async >( url: string, options?: FetchConfig ): Promise => { - const response = await fetchHandler( + const response = await fetch( paramsSerializer( addBaseUrl(normalizeUrl(url), options?.options?.baseURL), options?.options?.params @@ -162,7 +164,7 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => { data?: TSend, options?: FetchConfig ): Promise => { - const response = await fetchHandler( + const response = await fetch( paramsSerializer( addBaseUrl(normalizeUrl(url), options?.options?.baseURL), options?.options?.params @@ -182,7 +184,7 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => { data?: TSend, options?: FetchConfig ): Promise => { - const response = await fetchHandler( + const response = await fetch( paramsSerializer( addBaseUrl(normalizeUrl(url), options?.options?.baseURL), options?.options?.params @@ -201,7 +203,7 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => { url: string, options?: FetchConfig ): Promise => { - const response = await fetchHandler( + const response = await fetch( paramsSerializer( addBaseUrl(normalizeUrl(url), options?.options?.baseURL), options?.options?.params diff --git a/packages/core/admin/admin/src/utils/normalizeAPIError.ts b/packages/core/admin/admin/src/utils/normalizeAPIError.ts index f51c9746ac..6d3885eaab 100644 --- a/packages/core/admin/admin/src/utils/normalizeAPIError.ts +++ b/packages/core/admin/admin/src/utils/normalizeAPIError.ts @@ -1,8 +1,8 @@ import { getPrefixedId } from './getPrefixedId'; import type { ApiError } from '../hooks/useAPIErrorHandler'; +import type { FetchError } from '../utils/getFetchClient'; import type { errors } from '@strapi/utils'; -import type { AxiosError } from 'axios'; export interface NormalizeErrorOptions { name?: string; @@ -53,7 +53,7 @@ const validateErrorIsYupValidationError = ( * (e.g. outside of a React component). */ export function normalizeAPIError( - apiError: AxiosError<{ error: ApiError }>, + apiError: FetchError, intlMessagePrefixCallback?: NormalizeErrorOptions['intlMessagePrefixCallback'] ): | NormalizeErrorReturn diff --git a/packages/core/admin/admin/src/utils/tests/getFetchClient.test.ts b/packages/core/admin/admin/src/utils/tests/getFetchClient.test.ts index 42a5b9594c..c2505a2929 100644 --- a/packages/core/admin/admin/src/utils/tests/getFetchClient.test.ts +++ b/packages/core/admin/admin/src/utils/tests/getFetchClient.test.ts @@ -2,7 +2,7 @@ import { server } from '@tests/utils'; import { AxiosError } from 'axios'; import { rest } from 'msw'; -import { getFetchClient, instance } from '../getFetchClient'; +import { getFetchClient, FetchError } from '../getFetchClient'; describe('fetchClient', () => { it('should contain a paramsSerializer that can serialize a params object to a string', async () => { @@ -70,7 +70,7 @@ describe('getFetchClient', () => { try { await response.get('test-fetch-client'); } catch (err) { - const url = (err as AxiosError).config?.url; + const url = (err as FetchError).config?.url; expect(url).toBe('/test-fetch-client'); } }); diff --git a/packages/core/content-manager/admin/src/utils/api.ts b/packages/core/content-manager/admin/src/utils/api.ts index 1ddd6bc987..fe9fcae1ac 100644 --- a/packages/core/content-manager/admin/src/utils/api.ts +++ b/packages/core/content-manager/admin/src/utils/api.ts @@ -112,9 +112,9 @@ const fetchBaseQuery = } } catch (err) { /** - * Handle error of type AxiosError + * Handle error of type FetchError * - * This format mimics what we want from an AxiosError which is what the + * This format mimics what we want from an FetchError which is what the * rest of the app works with, except this format is "serializable" since * it goes into the redux store. * @@ -130,7 +130,7 @@ const fetchBaseQuery = /** * This will most likely be ApiError */ - return { data: undefined, error: err.response?.data.error }; + return { data: undefined, error: err.response?.data.error as any }; } else { return { data: undefined, @@ -138,7 +138,7 @@ const fetchBaseQuery = name: 'UnknownError', message: 'There was an unknown error response from the API', details: err.response, - status: err.response?.status, + status: err.response?.error.status, } as UnknownApiError, }; } diff --git a/packages/core/content-releases/admin/src/components/CMReleasesContainer.tsx b/packages/core/content-releases/admin/src/components/CMReleasesContainer.tsx index e508be5e6b..4329b2144d 100644 --- a/packages/core/content-releases/admin/src/components/CMReleasesContainer.tsx +++ b/packages/core/content-releases/admin/src/components/CMReleasesContainer.tsx @@ -25,7 +25,6 @@ import { import { LinkButton } from '@strapi/design-system/v2'; import { EmptyDocuments, Plus } from '@strapi/icons'; import { unstable_useDocument } from '@strapi/plugin-content-manager/strapi-admin'; -import { isAxiosError } from 'axios'; import { Formik, Form } from 'formik'; import { useIntl } from 'react-intl'; import { Link as ReactRouterLink, useParams } from 'react-router-dom'; @@ -144,7 +143,7 @@ const AddActionToReleaseModal = ({ } if ('error' in response) { - if (isAxiosError(response.error)) { + if (isFetchError(response.error)) { // Handle axios error toggleNotification({ type: 'danger', diff --git a/packages/core/content-releases/admin/src/components/ReleaseAction.tsx b/packages/core/content-releases/admin/src/components/ReleaseAction.tsx index 5b145d4086..9c1d65d150 100644 --- a/packages/core/content-releases/admin/src/components/ReleaseAction.tsx +++ b/packages/core/content-releases/admin/src/components/ReleaseAction.tsx @@ -5,6 +5,7 @@ import { useNotification, useQueryParams, useRBAC, + isFetchError, } from '@strapi/admin/strapi-admin'; import { Box, @@ -17,7 +18,6 @@ import { ModalFooter, } from '@strapi/design-system'; import { UID } from '@strapi/types'; -import { isAxiosError } from 'axios'; import { Formik, Form } from 'formik'; import { useIntl } from 'react-intl'; @@ -121,7 +121,7 @@ const ReleaseAction: BulkActionComponent = ({ documentIds, model }) => { } if ('error' in response) { - if (isAxiosError(response.error)) { + if (isFetchError(response.error)) { // Handle axios error toggleNotification({ type: 'warning', diff --git a/packages/core/content-releases/admin/src/components/ReleaseActionMenu.tsx b/packages/core/content-releases/admin/src/components/ReleaseActionMenu.tsx index a95c2d66d3..d6405d0549 100644 --- a/packages/core/content-releases/admin/src/components/ReleaseActionMenu.tsx +++ b/packages/core/content-releases/admin/src/components/ReleaseActionMenu.tsx @@ -1,10 +1,15 @@ import * as React from 'react'; -import { useAPIErrorHandler, useNotification, useAuth, useRBAC } from '@strapi/admin/strapi-admin'; +import { + useAPIErrorHandler, + useNotification, + useAuth, + useRBAC, + isFetchError, +} from '@strapi/admin/strapi-admin'; import { Flex, IconButton, Typography, Icon } from '@strapi/design-system'; import { Menu, Link } from '@strapi/design-system/v2'; import { Cross, More, Pencil } from '@strapi/icons'; -import { isAxiosError } from 'axios'; import { useIntl } from 'react-intl'; import { NavLink } from 'react-router-dom'; import styled from 'styled-components'; @@ -85,7 +90,7 @@ const DeleteReleaseActionItem = ({ releaseId, actionId }: DeleteReleaseActionIte } if ('error' in response) { - if (isAxiosError(response.error)) { + if (isFetchError(response.error)) { // Handle axios error toggleNotification({ type: 'danger', diff --git a/packages/core/content-releases/admin/src/pages/ReleaseDetailsPage.tsx b/packages/core/content-releases/admin/src/pages/ReleaseDetailsPage.tsx index aa4c084e27..11236ebc20 100644 --- a/packages/core/content-releases/admin/src/pages/ReleaseDetailsPage.tsx +++ b/packages/core/content-releases/admin/src/pages/ReleaseDetailsPage.tsx @@ -11,6 +11,7 @@ import { useNotification, useQueryParams, useRBAC, + isFetchError, } from '@strapi/admin/strapi-admin'; import { Button, @@ -43,7 +44,6 @@ import { ReleaseActionMenu } from '../components/ReleaseActionMenu'; import { ReleaseActionOptions } from '../components/ReleaseActionOptions'; import { ReleaseModal, FormValues } from '../components/ReleaseModal'; import { PERMISSIONS } from '../constants'; -import { isAxiosError } from '../services/baseQuery'; import { GetReleaseActionsQueryParams, useGetReleaseActionsQuery, @@ -253,7 +253,7 @@ const ReleaseDetailsLayout = ({ totalPublishedEntries, totalUnpublishedEntries, }); - } else if (isAxiosError(response.error)) { + } else if (isFetchError(response.error)) { // When the response returns an object with 'error', handle axios error toggleNotification({ type: 'danger', @@ -556,7 +556,7 @@ const ReleaseDetailsBody = ({ releaseId }: ReleaseDetailsBodyProps) => { }); if ('error' in response) { - if (isAxiosError(response.error)) { + if (isFetchError(response.error)) { // When the response returns an object with 'error', handle axios error toggleNotification({ type: 'danger', @@ -894,7 +894,7 @@ const ReleaseDetailsPage = () => { }), }); toggleEditReleaseModal(); - } else if (isAxiosError(response.error)) { + } else if (isFetchError(response.error)) { // When the response returns an object with 'error', handle axios error toggleNotification({ type: 'danger', @@ -916,8 +916,8 @@ const ReleaseDetailsPage = () => { if ('data' in response) { navigate('..'); - } else if (isAxiosError(response.error)) { - // When the response returns an object with 'error', handle axios error + } else if (isFetchError(response.error)) { + // When the response returns an object with 'error', handle fetch error toggleNotification({ type: 'danger', message: formatAPIError(response.error), diff --git a/packages/core/content-releases/admin/src/pages/ReleasesPage.tsx b/packages/core/content-releases/admin/src/pages/ReleasesPage.tsx index 748d2c542d..566204d9ed 100644 --- a/packages/core/content-releases/admin/src/pages/ReleasesPage.tsx +++ b/packages/core/content-releases/admin/src/pages/ReleasesPage.tsx @@ -8,6 +8,7 @@ import { useNotification, useQueryParams, useRBAC, + isFetchError, } from '@strapi/admin/strapi-admin'; import { useLicenseLimits } from '@strapi/admin/strapi-admin/ee'; import { @@ -40,7 +41,6 @@ import { GetReleases, type Release } from '../../../shared/contracts/releases'; import { RelativeTime as BaseRelativeTime } from '../components/RelativeTime'; import { ReleaseModal, FormValues } from '../components/ReleaseModal'; import { PERMISSIONS } from '../constants'; -import { isAxiosError } from '../services/baseQuery'; import { useGetReleasesQuery, GetReleasesQueryParams, @@ -274,7 +274,7 @@ const ReleasesPage = () => { trackUsage('didCreateRelease'); navigate(response.data.data.id.toString()); - } else if (isAxiosError(response.error)) { + } else if (isFetchError(response.error)) { // When the response returns an object with 'error', handle axios error toggleNotification({ type: 'danger', diff --git a/packages/core/content-releases/admin/src/services/baseQuery.ts b/packages/core/content-releases/admin/src/services/baseQuery.ts index e974d187cf..dda56f200a 100644 --- a/packages/core/content-releases/admin/src/services/baseQuery.ts +++ b/packages/core/content-releases/admin/src/services/baseQuery.ts @@ -1,6 +1,9 @@ -import { getFetchClient, type FetchResponse, type FetchConfig } from '@strapi/admin/strapi-admin'; - -import type { AxiosError } from 'axios'; +import { + getFetchClient, + type FetchResponse, + type FetchConfig, + type FetchError, +} from '@strapi/admin/strapi-admin'; export interface QueryArguments { url: string; @@ -39,11 +42,11 @@ const fetchBaseQuery = async ({ const result = await get>(url, config); return { data: result.data }; } catch (error) { - const err = error as AxiosError; + const err = error as FetchError; /** - * Handle error of type AxiosError + * Handle error of type FetchError * - * This format mimics what we want from an AxiosError which is what the + * This format mimics what we want from an FetchError which is what the * rest of the app works with, except this format is "serializable" since * it goes into the redux store. * @@ -51,7 +54,7 @@ const fetchBaseQuery = async ({ */ return { error: { - status: err.response?.status, + status: err.response?.error.status, code: err.code, response: { data: err.response?.data, @@ -61,24 +64,4 @@ const fetchBaseQuery = async ({ } }; -/* ------------------------------------------------------------------------------------------------- - * Axios error - * -----------------------------------------------------------------------------------------------*/ - -/** - * This asserts the errors from redux-toolkit-query are - * axios errors so we can pass them to our utility functions - * to correctly render error messages. - */ -const isAxiosError = (err: unknown): err is AxiosError<{ error: any }> => { - return ( - typeof err === 'object' && - err !== null && - 'response' in err && - typeof err.response === 'object' && - err.response !== null && - 'data' in err.response - ); -}; - -export { isAxiosError, fetchBaseQuery }; +export { fetchBaseQuery }; diff --git a/packages/core/review-workflows/admin/src/services/api.ts b/packages/core/review-workflows/admin/src/services/api.ts index 0ffd488f86..ea53d0fd3b 100644 --- a/packages/core/review-workflows/admin/src/services/api.ts +++ b/packages/core/review-workflows/admin/src/services/api.ts @@ -1,10 +1,10 @@ import { createApi } from '@reduxjs/toolkit/query/react'; -import { axiosBaseQuery, type UnknownApiError } from '../utils/api'; +import { fetchBaseQuery, type UnknownApiError } from '../utils/api'; const reviewWorkflowsApi = createApi({ reducerPath: 'reviewWorkflowsApi', - baseQuery: axiosBaseQuery(), + baseQuery: fetchBaseQuery(), tagTypes: ['ReviewWorkflow', 'ReviewWorkflowStage'], endpoints: () => ({}), }); diff --git a/packages/core/review-workflows/admin/src/utils/api.ts b/packages/core/review-workflows/admin/src/utils/api.ts index 71fcdff74b..1ec285b559 100644 --- a/packages/core/review-workflows/admin/src/utils/api.ts +++ b/packages/core/review-workflows/admin/src/utils/api.ts @@ -1,11 +1,12 @@ import { SerializedError } from '@reduxjs/toolkit'; import { BaseQueryFn } from '@reduxjs/toolkit/query'; -import { getFetchClient, ApiError, FetchConfig } from '@strapi/admin/strapi-admin'; -import { isAxiosError, type AxiosRequestConfig } from 'axios'; +import { + getFetchClient, + isFetchError, + type ApiError, + type FetchConfig, +} from '@strapi/admin/strapi-admin'; -/* ------------------------------------------------------------------------------------------------- - * Axios data - * -----------------------------------------------------------------------------------------------*/ export interface QueryArguments { url: string; method?: string; @@ -22,7 +23,7 @@ export interface UnknownApiError { export type BaseQueryError = ApiError | UnknownApiError; -const axiosBaseQuery = +const fetchBaseQuery = (): BaseQueryFn => async (query, { signal }) => { try { @@ -69,16 +70,16 @@ const axiosBaseQuery = } } catch (err) { /** - * Handle error of type AxiosError + * Handle error of type FetchError * - * This format mimics what we want from an AxiosError which is what the + * This format mimics what we want from an FetchError which is what the * rest of the app works with, except this format is "serializable" since * it goes into the redux store. * * NOTE – passing the whole response will highlight this "serializability" issue. */ - if (isAxiosError(err)) { + if (isFetchError(err)) { if ( typeof err.response?.data === 'object' && err.response?.data !== null && @@ -95,7 +96,7 @@ const axiosBaseQuery = name: 'UnknownError', message: 'There was an unknown error response from the API', details: err.response?.data, - status: err.response?.status, + status: err.response?.error.status, } as UnknownApiError, }; } @@ -117,4 +118,4 @@ const isBaseQueryError = (error: BaseQueryError | SerializedError): error is Bas return error.name !== undefined; }; -export { axiosBaseQuery, isBaseQueryError }; +export { fetchBaseQuery, isBaseQueryError }; diff --git a/packages/plugins/documentation/admin/src/services/api.ts b/packages/plugins/documentation/admin/src/services/api.ts index 7d08311e21..cbd824ab01 100644 --- a/packages/plugins/documentation/admin/src/services/api.ts +++ b/packages/plugins/documentation/admin/src/services/api.ts @@ -1,7 +1,7 @@ import { createApi } from '@reduxjs/toolkit/query/react'; import { DocumentInfos } from '../types'; -import { axiosBaseQuery } from '../utils/baseQuery'; +import { baseQuery } from '../utils/baseQuery'; type SettingsInput = { restrictedAccess: boolean; @@ -10,7 +10,7 @@ type SettingsInput = { const api = createApi({ reducerPath: 'plugin::documentation', - baseQuery: axiosBaseQuery({ + baseQuery: baseQuery({ options: { baseURL: '/documentation', }, diff --git a/packages/plugins/documentation/admin/src/utils/baseQuery.ts b/packages/plugins/documentation/admin/src/utils/baseQuery.ts index 1c1613f7ac..d732d64535 100644 --- a/packages/plugins/documentation/admin/src/utils/baseQuery.ts +++ b/packages/plugins/documentation/admin/src/utils/baseQuery.ts @@ -1,11 +1,12 @@ import { SerializedError } from '@reduxjs/toolkit'; import { BaseQueryFn } from '@reduxjs/toolkit/query'; -import { getFetchClient, ApiError, FetchConfig } from '@strapi/strapi/admin'; -import { isAxiosError, type AxiosRequestConfig } from 'axios'; +import { + getFetchClient, + isFetchError, + type ApiError, + type FetchConfig, +} from '@strapi/strapi/admin'; -/* ------------------------------------------------------------------------------------------------- - * Axios data - * -----------------------------------------------------------------------------------------------*/ export interface QueryArguments { url: string; method?: string; @@ -22,7 +23,7 @@ export interface UnknownApiError { export type BaseQueryError = ApiError | UnknownApiError; -const axiosBaseQuery = +const baseQuery = (config: FetchConfig): BaseQueryFn => async (query, { signal }) => { try { @@ -69,16 +70,16 @@ const axiosBaseQuery = } } catch (err) { /** - * Handle error of type AxiosError + * Handle error of type FetchError * - * This format mimics what we want from an AxiosError which is what the + * This format mimics what we want from an FetchError which is what the * rest of the app works with, except this format is "serializable" since * it goes into the redux store. * * NOTE – passing the whole response will highlight this "serializability" issue. */ - if (isAxiosError(err)) { + if (isFetchError(err)) { if ( typeof err.response?.data === 'object' && err.response?.data !== null && @@ -95,7 +96,7 @@ const axiosBaseQuery = name: 'UnknownError', message: 'There was an unknown error response from the API', details: err.response?.data, - status: err.response?.status, + status: err.response?.error?.status, } as UnknownApiError, }; } @@ -117,4 +118,4 @@ const isBaseQueryError = (error: BaseQueryError | SerializedError): error is Bas return error.name !== undefined; }; -export { axiosBaseQuery, isBaseQueryError }; +export { baseQuery, isBaseQueryError }; diff --git a/packages/plugins/i18n/admin/src/services/api.ts b/packages/plugins/i18n/admin/src/services/api.ts index aa905bb167..201f2fd071 100644 --- a/packages/plugins/i18n/admin/src/services/api.ts +++ b/packages/plugins/i18n/admin/src/services/api.ts @@ -1,10 +1,10 @@ import { createApi } from '@reduxjs/toolkit/query/react'; -import { axiosBaseQuery, type UnknownApiError } from '../utils/baseQuery'; +import { fetchBaseQuery, type UnknownApiError } from '../utils/baseQuery'; const i18nApi = createApi({ reducerPath: 'i18nApi', - baseQuery: axiosBaseQuery(), + baseQuery: fetchBaseQuery(), tagTypes: ['Locale'], endpoints: () => ({}), }); diff --git a/packages/plugins/i18n/admin/src/utils/baseQuery.ts b/packages/plugins/i18n/admin/src/utils/baseQuery.ts index 20e9730112..1ec285b559 100644 --- a/packages/plugins/i18n/admin/src/utils/baseQuery.ts +++ b/packages/plugins/i18n/admin/src/utils/baseQuery.ts @@ -1,11 +1,12 @@ import { SerializedError } from '@reduxjs/toolkit'; import { BaseQueryFn } from '@reduxjs/toolkit/query'; -import { getFetchClient, ApiError, type FetchConfig } from '@strapi/admin/strapi-admin'; -import { isAxiosError } from 'axios'; +import { + getFetchClient, + isFetchError, + type ApiError, + type FetchConfig, +} from '@strapi/admin/strapi-admin'; -/* ------------------------------------------------------------------------------------------------- - * Axios data - * -----------------------------------------------------------------------------------------------*/ export interface QueryArguments { url: string; method?: string; @@ -22,7 +23,7 @@ export interface UnknownApiError { export type BaseQueryError = ApiError | UnknownApiError; -const axiosBaseQuery = +const fetchBaseQuery = (): BaseQueryFn => async (query, { signal }) => { try { @@ -69,16 +70,16 @@ const axiosBaseQuery = } } catch (err) { /** - * Handle error of type AxiosError + * Handle error of type FetchError * - * This format mimics what we want from an AxiosError which is what the + * This format mimics what we want from an FetchError which is what the * rest of the app works with, except this format is "serializable" since * it goes into the redux store. * * NOTE – passing the whole response will highlight this "serializability" issue. */ - if (isAxiosError(err)) { + if (isFetchError(err)) { if ( typeof err.response?.data === 'object' && err.response?.data !== null && @@ -95,7 +96,7 @@ const axiosBaseQuery = name: 'UnknownError', message: 'There was an unknown error response from the API', details: err.response?.data, - status: err.response?.status, + status: err.response?.error.status, } as UnknownApiError, }; } @@ -117,4 +118,4 @@ const isBaseQueryError = (error: BaseQueryError | SerializedError): error is Bas return error.name !== undefined; }; -export { axiosBaseQuery, isBaseQueryError }; +export { fetchBaseQuery, isBaseQueryError };