chore: remove axios from packages and edit some tests

This commit is contained in:
Bassel Kanso 2024-04-15 19:47:36 +03:00
parent 9e8dcb640e
commit f41be330aa
21 changed files with 124 additions and 218 deletions

View File

@ -1,31 +1,9 @@
import { renderHook } from '@tests/utils';
import { AxiosError, AxiosHeaders } from 'axios';
import { useAPIErrorHandler, ApiError } from '../useAPIErrorHandler';
import { FetchError } from '../../utils/getFetchClient';
import { useAPIErrorHandler } from '../useAPIErrorHandler';
describe('useAPIErrorHandler', () => {
class Err extends AxiosError<{ error: ApiError }> {
constructor(error: ApiError) {
super(
undefined,
undefined,
undefined,
{},
{
statusText: 'Bad Request',
status: 400,
headers: new AxiosHeaders(),
config: {
headers: new AxiosHeaders(),
},
data: {
error,
},
}
);
}
}
beforeEach(() => {
jest.clearAllMocks();
});
@ -40,10 +18,13 @@ describe('useAPIErrorHandler', () => {
const { result } = renderHook(() => useAPIErrorHandler());
const message = result.current.formatAPIError(
new Err({
name: 'ApplicationError',
message: 'Field contains errors',
details: {},
new FetchError('Error occured', {
data: null,
error: {
name: 'ApplicationError',
message: 'Field contains errors',
details: {},
},
})
);
@ -54,21 +35,24 @@ describe('useAPIErrorHandler', () => {
const { result } = renderHook(() => useAPIErrorHandler());
const message = result.current.formatAPIError(
new Err({
name: 'ValidationError',
message: '',
details: {
errors: [
{
path: ['field', '0', 'name'],
message: 'Field contains errors',
},
new FetchError('Fetch Error Occured', {
data: null,
error: {
name: 'ValidationError',
message: '',
details: {
errors: [
{
path: ['field', '0', 'name'],
message: 'Field contains errors',
},
{
path: ['field'],
message: 'Field must be unique',
},
],
{
path: ['field'],
message: 'Field must be unique',
},
],
},
},
})
);
@ -79,20 +63,15 @@ describe('useAPIErrorHandler', () => {
test('formats AxiosErrors', async () => {
const { result } = renderHook(() => useAPIErrorHandler());
const axiosError = new AxiosError(
const fetchError = new FetchError(
'Error message',
'409',
undefined,
{},
// @ts-expect-error we're testing that it can handle axios errors
// @ts-expect-error we're testing that it can handle fetch errors
{
status: 405,
data: { message: 'Error message' },
}
);
// @ts-expect-error we're testing that it can handle axios errors
const message = result.current.formatAPIError(axiosError);
const message = result.current.formatAPIError(fetchError);
expect(message).toBe('Error message');
});

View File

@ -126,7 +126,7 @@ export function useAPIErrorHandler(
const formatError = React.useCallback(
(error: FetchError) => {
// Try to normalize the passed error first. This will fail for e.g. network
// errors which are thrown by Axios directly.
// errors which are thrown by fetchClient directly.
try {
const formattedErr = formatAPIError(error, { intlMessagePrefixCallback, formatMessage });

View File

@ -9,23 +9,23 @@ const STORAGE_KEYS = {
type FetchParams = Parameters<typeof fetch>;
type FetchURL = FetchParams[0];
export type FetchOptions = FetchParams[1];
export type FetchResponse<TData = unknown> = {
data: TData;
};
type Options = {
export type FetchOptions = {
params?: any;
baseURL?: string;
signal?: AbortSignal;
};
export type FetchConfig = {
options?: Options;
fetchConfig?: FetchParams[1];
baseURL?: string;
};
type ErrorResponse = {
data: any;
error: ApiError & { status: number };
error: ApiError & { status?: number };
};
export class FetchError extends Error {
@ -39,7 +39,7 @@ export class FetchError extends Error {
this.name = 'FetchError';
this.message = message;
this.response = response;
this.code = response?.error.status;
this.code = response?.error?.status;
// Ensure correct stack trace in error object
if (Error.captureStackTrace) {
@ -66,18 +66,24 @@ const hasProtocol = (url: string) => new RegExp('^(?:[a-z+]+:)?//', 'i').test(ur
const normalizeUrl = (url: string) => (hasProtocol(url) ? url : addPrependingSlash(url));
type FetchClient = {
get: <TData = unknown, R = FetchResponse<TData>>(url: string, config?: FetchConfig) => Promise<R>;
get: <TData = unknown, R = FetchResponse<TData>>(
url: string,
config?: FetchOptions
) => Promise<R>;
put: <TData = unknown, R = FetchResponse<TData>, TSend = unknown>(
url: string,
data?: TSend,
config?: FetchConfig
config?: FetchOptions
) => Promise<R>;
post: <TData = unknown, R = FetchResponse<TData>, TSend = unknown>(
url: string,
data?: TSend,
config?: FetchConfig
config?: FetchOptions
) => Promise<R>;
del: <TData = unknown, R = FetchResponse<TData>>(
url: string,
config?: FetchOptions
) => Promise<R>;
del: <TData = unknown, R = FetchResponse<TData>>(url: string, config?: FetchConfig) => Promise<R>;
};
/**
@ -101,7 +107,7 @@ type FetchClient = {
* ```
*/
const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => {
const { options } = defaultOptions;
const baseURL = defaultOptions.baseURL ?? window.strapi.backendURL;
const headers = new Headers({
Accept: 'application/json',
'Content-Type': 'application/json',
@ -129,30 +135,19 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => {
return url;
};
const addBaseUrl = (url: FetchURL, clientBaseURL?: string) => {
if (clientBaseURL) {
return `${clientBaseURL}${url}`;
}
if (options?.baseURL) {
return `${options?.baseURL}${url}`;
}
const baseURL = window.strapi.backendURL;
const addBaseUrl = (url: FetchURL) => {
return `${baseURL}${url}`;
};
const fetchClient: FetchClient = {
get: async <TData = unknown, R = FetchResponse<TData>>(
url: string,
options?: FetchConfig
options?: FetchOptions
): Promise<R> => {
const response = await fetch(
paramsSerializer(
addBaseUrl(normalizeUrl(url), options?.options?.baseURL),
options?.options?.params
),
paramsSerializer(addBaseUrl(normalizeUrl(url)), options?.params),
{
...defaultOptions.fetchConfig,
...options?.fetchConfig,
...options,
method: 'GET',
headers,
}
@ -162,16 +157,12 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => {
post: async <TData = unknown, R = FetchResponse<TData>, TSend = unknown>(
url: string,
data?: TSend,
options?: FetchConfig
options?: FetchOptions
): Promise<R> => {
const response = await fetch(
paramsSerializer(
addBaseUrl(normalizeUrl(url), options?.options?.baseURL),
options?.options?.params
),
paramsSerializer(addBaseUrl(normalizeUrl(url)), options?.params),
{
...defaultOptions?.fetchConfig,
...options?.fetchConfig,
...options,
method: 'POST',
headers,
body: JSON.stringify(data),
@ -182,16 +173,12 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => {
put: async <TData = unknown, R = FetchResponse<TData>, TSend = unknown>(
url: string,
data?: TSend,
options?: FetchConfig
options?: FetchOptions
): Promise<R> => {
const response = await fetch(
paramsSerializer(
addBaseUrl(normalizeUrl(url), options?.options?.baseURL),
options?.options?.params
),
paramsSerializer(addBaseUrl(normalizeUrl(url)), options?.params),
{
...defaultOptions?.fetchConfig,
...options?.fetchConfig,
...options,
method: 'PUT',
headers,
body: JSON.stringify(data),
@ -201,16 +188,12 @@ const getFetchClient = (defaultOptions: FetchConfig = {}): FetchClient => {
},
del: async <TData = unknown, R = FetchResponse<TData>>(
url: string,
options?: FetchConfig
options?: FetchOptions
): Promise<R> => {
const response = await fetch(
paramsSerializer(
addBaseUrl(normalizeUrl(url), options?.options?.baseURL),
options?.options?.params
),
paramsSerializer(addBaseUrl(normalizeUrl(url)), options?.params),
{
...defaultOptions?.fetchConfig,
...options?.fetchConfig,
...options,
method: 'DELETE',
headers,
}

View File

@ -59,7 +59,7 @@ export function normalizeAPIError(
| NormalizeErrorReturn
| { name: string; message: string | null; errors: NormalizeErrorReturn[] }
| null {
const error = apiError.response?.data.error;
const error = apiError.response?.error;
if (error) {
// some errors carry multiple errors (such as ValidationError)
@ -72,7 +72,6 @@ export function normalizeAPIError(
),
};
}
return normalizeError(error, { intlMessagePrefixCallback });
}

View File

@ -12,9 +12,7 @@ const historyVersionsApi = contentManagerApi.injectEndpoints({
url: `/content-manager/history-versions`,
method: 'GET',
config: {
options: {
params,
},
params,
},
};
},

View File

@ -30,9 +30,7 @@ const documentApi = contentManagerApi.injectEndpoints({
url: `/content-manager/collection-types/${model}/auto-clone/${sourceId}`,
method: 'POST',
config: {
options: {
params: query,
},
params: query,
},
}),
invalidatesTags: (_result, _error, { model }) => [{ type: 'Document', id: `${model}_LIST` }],
@ -49,9 +47,7 @@ const documentApi = contentManagerApi.injectEndpoints({
method: 'POST',
data,
config: {
options: {
params,
},
params,
},
}),
invalidatesTags: (_result, _error, { model }) => [{ type: 'Document', id: `${model}_LIST` }],
@ -72,9 +68,7 @@ const documentApi = contentManagerApi.injectEndpoints({
method: 'POST',
data,
config: {
options: {
params,
},
params,
},
}),
invalidatesTags: (result, _error, { model }) => [
@ -96,9 +90,7 @@ const documentApi = contentManagerApi.injectEndpoints({
}`,
method: 'DELETE',
config: {
options: {
params,
},
params,
},
}),
invalidatesTags: (_result, _error, { collectionType, model }) => [
@ -133,9 +125,7 @@ const documentApi = contentManagerApi.injectEndpoints({
: `/content-manager/${collectionType}/${model}/actions/discard`,
method: 'POST',
config: {
options: {
params,
},
params,
},
}),
invalidatesTags: (_result, _error, { collectionType, model, documentId }) => {
@ -165,9 +155,7 @@ const documentApi = contentManagerApi.injectEndpoints({
url: `/content-manager/collection-types/${model}`,
method: 'GET',
config: {
options: {
params,
},
params,
},
}),
providesTags: (result, _error, arg) => {
@ -198,9 +186,7 @@ const documentApi = contentManagerApi.injectEndpoints({
: `/content-manager/${collectionType}/${model}/actions/countDraftRelations`,
method: 'GET',
config: {
options: {
params,
},
params,
},
}),
}),
@ -223,9 +209,7 @@ const documentApi = contentManagerApi.injectEndpoints({
url: `/content-manager/${collectionType}/${model}${documentId ? `/${documentId}` : ''}`,
method: 'GET',
config: {
options: {
params,
},
params,
},
});
@ -263,9 +247,7 @@ const documentApi = contentManagerApi.injectEndpoints({
url: `/content-manager/collection-types/${model}/actions/countManyEntriesDraftRelations`,
method: 'GET',
config: {
options: {
params,
},
params,
},
}),
transformResponse: (response: CountManyEntriesDraftRelations.Response) => response.data,
@ -289,9 +271,7 @@ const documentApi = contentManagerApi.injectEndpoints({
method: 'POST',
data,
config: {
options: {
params,
},
params,
},
}),
invalidatesTags: (_result, _error, { collectionType, model, documentId }) => {
@ -331,9 +311,7 @@ const documentApi = contentManagerApi.injectEndpoints({
method: 'PUT',
data,
config: {
options: {
params,
},
params,
},
}),
invalidatesTags: (_result, _error, { collectionType, model, documentId }) => {
@ -362,9 +340,7 @@ const documentApi = contentManagerApi.injectEndpoints({
method: 'POST',
data,
config: {
options: {
params,
},
params,
},
}),
invalidatesTags: (_result, _error, { collectionType, model, documentId }) => {

View File

@ -45,9 +45,7 @@ const relationsApi = contentManagerApi.injectEndpoints({
url: `/content-manager/relations/${model}/${id}/${targetField}`,
method: 'GET',
config: {
options: {
params,
},
params,
},
};
},
@ -117,9 +115,7 @@ const relationsApi = contentManagerApi.injectEndpoints({
url: `/content-manager/relations/${model}/${targetField}`,
method: 'GET',
config: {
options: {
params,
},
params,
},
};
},

View File

@ -20,9 +20,7 @@ const uidApi = contentManagerApi.injectEndpoints({
method: 'POST',
data,
config: {
options: {
params,
},
params,
},
};
},
@ -39,9 +37,7 @@ const uidApi = contentManagerApi.injectEndpoints({
method: 'POST',
data,
config: {
options: {
params,
},
params,
},
}),
transformResponse: (response: GenerateUID.Response) => response.data,
@ -57,9 +53,7 @@ const uidApi = contentManagerApi.injectEndpoints({
method: 'POST',
data,
config: {
options: {
params,
},
params,
},
}),
}),

View File

@ -4,7 +4,7 @@ import {
getFetchClient,
ApiError,
isFetchError,
type FetchConfig,
type FetchOptions,
} from '@strapi/admin/strapi-admin';
interface Query {
@ -51,7 +51,7 @@ export interface QueryArguments {
url: string;
method?: string;
data?: unknown;
config?: FetchConfig;
config?: FetchOptions;
}
export interface UnknownApiError {
@ -71,7 +71,7 @@ const fetchBaseQuery =
if (typeof query === 'string') {
const result = await get(query, {
fetchConfig: { signal },
signal,
});
return { data: result.data };
} else {
@ -79,24 +79,24 @@ const fetchBaseQuery =
if (method === 'POST') {
const result = await post(url, data, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}
if (method === 'DELETE') {
const result = await del(url, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}
if (method === 'PUT') {
const result = await put(url, data, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}
@ -105,8 +105,8 @@ const fetchBaseQuery =
* Default is GET.
*/
const result = await get(url, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}

View File

@ -64,7 +64,6 @@
"@strapi/icons": "1.16.0",
"@strapi/types": "5.0.0-beta.2",
"@strapi/utils": "5.0.0-beta.2",
"axios": "1.6.8",
"codemirror5": "npm:codemirror@^5.65.11",
"date-fns": "2.30.0",
"fractional-indexing": "3.2.0",

View File

@ -1,7 +1,7 @@
import {
getFetchClient,
type FetchResponse,
type FetchConfig,
type FetchOptions,
type FetchError,
} from '@strapi/admin/strapi-admin';
@ -9,7 +9,7 @@ export interface QueryArguments<TSend> {
url: string;
method: 'PUT' | 'GET' | 'POST' | 'DELETE';
data?: TSend;
config?: FetchConfig;
config?: FetchOptions;
}
const fetchBaseQuery = async <TData = unknown, TSend = unknown>({

View File

@ -63,9 +63,7 @@ const releaseApi = createApi({
url: '/content-releases',
method: 'GET',
config: {
options: {
params,
},
params,
},
};
},
@ -93,14 +91,12 @@ const releaseApi = createApi({
url: '/content-releases',
method: 'GET',
config: {
options: {
params: {
page: page || 1,
pageSize: pageSize || 16,
filters: filters || {
releasedAt: {
$notNull: false,
},
params: {
page: page || 1,
pageSize: pageSize || 16,
filters: filters || {
releasedAt: {
$notNull: false,
},
},
},
@ -146,9 +142,7 @@ const releaseApi = createApi({
url: `/content-releases/${releaseId}/actions`,
method: 'GET',
config: {
options: {
params,
},
params,
},
};
},

View File

@ -59,7 +59,6 @@
"@strapi/icons": "1.16.0",
"@strapi/types": "workspace:*",
"@strapi/utils": "5.0.0-beta.2",
"axios": "1.6.8",
"date-fns": "2.30.0",
"date-fns-tz": "2.0.1",
"formik": "2.4.5",

View File

@ -48,7 +48,6 @@
"@reduxjs/toolkit": "1.9.7",
"@strapi/design-system": "1.17.0",
"@strapi/icons": "1.16.0",
"axios": "1.6.8",
"react-helmet": "^6.1.0",
"react-intl": "6.6.2",
"react-redux": "8.1.3",

View File

@ -52,7 +52,6 @@
"@strapi/icons": "1.16.0",
"@strapi/provider-upload-local": "5.0.0-beta.2",
"@strapi/utils": "5.0.0-beta.2",
"axios": "1.6.8",
"byte-size": "7.0.1",
"cropperjs": "1.6.1",
"date-fns": "2.30.0",

View File

@ -11,9 +11,7 @@ type SettingsInput = {
const api = createApi({
reducerPath: 'plugin::documentation',
baseQuery: baseQuery({
options: {
baseURL: '/documentation',
},
baseURL: '/documentation',
}),
tagTypes: ['DocumentInfos'],
endpoints: (builder) => {

View File

@ -4,6 +4,7 @@ import {
getFetchClient,
isFetchError,
type ApiError,
type FetchOptions,
type FetchConfig,
} from '@strapi/strapi/admin';
@ -11,7 +12,7 @@ export interface QueryArguments {
url: string;
method?: string;
data?: unknown;
config?: FetchConfig;
config?: FetchOptions;
}
export interface UnknownApiError {
@ -30,31 +31,31 @@ const baseQuery =
const { get, post, del, put } = getFetchClient(config);
if (typeof query === 'string') {
const result = await get(query, { fetchConfig: { signal } });
const result = await get(query, { signal });
return { data: result.data };
} else {
const { url, method = 'GET', data, config } = query;
if (method === 'POST') {
const result = await post(url, data, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}
if (method === 'DELETE') {
const result = await del(url, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}
if (method === 'PUT') {
const result = await put(url, data, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}
@ -63,8 +64,8 @@ const baseQuery =
* Default is GET.
*/
const result = await get(url, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}

View File

@ -57,7 +57,6 @@
"@strapi/design-system": "1.17.0",
"@strapi/icons": "1.16.0",
"@strapi/utils": "5.0.0-beta.2",
"axios": "1.6.8",
"bcryptjs": "2.4.3",
"cheerio": "^1.0.0-rc.12",
"formik": "2.4.5",

View File

@ -4,14 +4,14 @@ import {
getFetchClient,
isFetchError,
type ApiError,
type FetchConfig,
type FetchOptions,
} from '@strapi/admin/strapi-admin';
export interface QueryArguments {
url: string;
method?: string;
data?: unknown;
config?: FetchConfig;
config?: FetchOptions;
}
export interface UnknownApiError {
@ -30,31 +30,31 @@ const fetchBaseQuery =
const { get, post, del, put } = getFetchClient();
if (typeof query === 'string') {
const result = await get(query, { fetchConfig: { signal } });
const result = await get(query, { signal });
return { data: result.data };
} else {
const { url, method = 'GET', data, config } = query;
if (method === 'POST') {
const result = await post(url, data, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}
if (method === 'DELETE') {
const result = await del(url, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}
if (method === 'PUT') {
const result = await put(url, data, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}
@ -63,8 +63,8 @@ const fetchBaseQuery =
* Default is GET.
*/
const result = await get(url, {
options: { ...config?.options },
fetchConfig: { ...config?.fetchConfig, signal },
...config,
signal,
});
return { data: result.data };
}

View File

@ -56,7 +56,6 @@
"@strapi/design-system": "1.17.0",
"@strapi/icons": "1.16.0",
"@strapi/utils": "5.0.0-beta.2",
"axios": "1.6.8",
"lodash": "4.17.21",
"qs": "6.11.1",
"react-intl": "6.6.2",

View File

@ -6961,7 +6961,6 @@ __metadata:
"@testing-library/user-event": "npm:14.4.3"
"@types/koa": "npm:2.13.4"
"@types/styled-components": "npm:5.1.34"
axios: "npm:1.6.8"
date-fns: "npm:2.30.0"
date-fns-tz: "npm:2.0.1"
formik: "npm:2.4.5"
@ -7364,7 +7363,6 @@ __metadata:
"@testing-library/react": "npm:14.0.0"
"@types/jest": "npm:29.5.2"
"@types/lodash": "npm:^4.14.191"
axios: "npm:1.6.8"
codemirror5: "npm:codemirror@^5.65.11"
date-fns: "npm:2.30.0"
fractional-indexing: "npm:3.2.0"
@ -7471,7 +7469,6 @@ __metadata:
"@types/koa": "npm:2.13.4"
"@types/koa-session": "npm:6.4.1"
"@types/swagger-ui-dist": "npm:3.30.4"
axios: "npm:1.6.8"
bcryptjs: "npm:2.4.3"
cheerio: "npm:^1.0.0-rc.12"
formik: "npm:2.4.5"
@ -7596,7 +7593,6 @@ __metadata:
"@strapi/utils": "npm:5.0.0-beta.2"
"@testing-library/react": "npm:14.0.0"
"@testing-library/user-event": "npm:14.4.3"
axios: "npm:1.6.8"
lodash: "npm:4.17.21"
msw: "npm:1.3.0"
qs: "npm:6.11.1"
@ -7657,7 +7653,6 @@ __metadata:
"@types/koa": "npm:2.13.4"
"@types/koa-range": "npm:0.3.5"
"@types/koa-static": "npm:4.0.2"
axios: "npm:1.6.8"
byte-size: "npm:7.0.1"
cropperjs: "npm:1.6.1"
date-fns: "npm:2.30.0"
@ -7867,7 +7862,6 @@ __metadata:
"@strapi/plugin-content-manager": "npm:5.0.0-beta.2"
"@strapi/types": "npm:5.0.0-beta.2"
"@strapi/utils": "npm:5.0.0-beta.2"
axios: "npm:1.6.8"
msw: "npm:1.3.0"
react: "npm:^18.2.0"
react-dom: "npm:^18.2.0"