Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change: [M3-7396] - Update axios to 1.6.1 #9911

Merged
merged 7 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Tech Stories
---

Update `axios` to `1.6.1` ([#9911](https://github.com/linode/manager/pull/9911))
6 changes: 3 additions & 3 deletions packages/api-v4/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"unpkg": "./lib/index.global.js",
"dependencies": {
"@linode/validation": "*",
"axios": "~0.21.4",
"axios": "~1.6.1",
"ipaddr.js": "^2.0.0",
"yup": "^0.32.9"
},
Expand All @@ -59,14 +59,14 @@
"devDependencies": {
"@types/node": "^12.7.1",
"@types/yup": "^0.29.13",
"axios-mock-adapter": "^1.18.1",
"axios-mock-adapter": "^1.22.0",
"concurrently": "^4.1.1",
"eslint": "^6.8.0",
"eslint-plugin-ramda": "^2.5.1",
"eslint-plugin-sonarjs": "^0.5.0",
"lint-staged": "^13.2.2",
"prettier": "~2.2.1",
"tsup": "^6.7.0",
"tsup": "^7.2.0",
"vitest": "^0.34.6"
},
"lint-staged": {
Expand Down
53 changes: 29 additions & 24 deletions packages/api-v4/src/request.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import Axios, { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import Axios, {
AxiosError,
AxiosHeaders,
AxiosRequestConfig,
AxiosResponse,
} from 'axios';
import { ValidationError, AnySchema } from 'yup';
import { APIError, Filter, Params } from './types';

Expand All @@ -14,14 +19,16 @@ export const baseRequest = Axios.create({

baseRequest.interceptors.request.use((config) => {
const isRunningInNode = typeof process === 'object';
const newConfig = {
...config,
headers: {
...config.headers,
'User-Agent': 'linodejs',
},
};
return isRunningInNode ? newConfig : config;

if (!isRunningInNode) {
return config;
}

const headers = new AxiosHeaders(config.headers);

headers.set('User-Agent', 'linodejs');

return { ...config, headers };
});

/**
Expand All @@ -34,13 +41,11 @@ baseRequest.interceptors.request.use((config) => {
*/
export const setToken = (token: string) => {
return baseRequest.interceptors.request.use((config) => {
return {
...config,
headers: {
...config.headers,
Authorization: `Bearer ${token}`,
},
};
const headers = new AxiosHeaders(config.headers);

headers.set('Authorization', `Bearer ${token}`);

return { ...config, headers };
});
};

Expand Down Expand Up @@ -205,7 +210,9 @@ export const mockAPIError = (
status,
statusText,
headers: {},
config: {},
config: {
headers: new AxiosHeaders(),
},
})
),
process.env.NODE_ENV === 'test' ? 0 : 250
Expand Down Expand Up @@ -258,13 +265,11 @@ export const CancellableRequest = <T>(
*/
export const setUserAgentPrefix = (prefix: string) => {
return baseRequest.interceptors.request.use((config) => {
return {
...config,
headers: {
...config.headers,
'User-Agent': `${prefix}/${config.headers['User-Agent']}`,
},
};
const headers = new AxiosHeaders(config.headers);

headers.set('User-Agent', `${prefix}/${config.headers['User-Agent']}`);

return { ...config, headers };
});
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Tech Stories
---

Update `axios` to `1.6.1` ([#9911](https://github.com/linode/manager/pull/9911))
25 changes: 9 additions & 16 deletions packages/manager/cypress/support/util/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import { baseRequest } from '@linode/api-v4';
import { AxiosHeaders } from 'axios';

// Note: This file is imported by Cypress plugins, and indirectly by Cypress
// tests. Because Cypress has not been initiated when plugins are executed, we
Expand All @@ -26,23 +27,15 @@ export const defaultApiRoot = 'https://api.linode.com/v4';
*/
export const configureLinodeApi = (accessToken: string, baseUrl?: string) => {
baseRequest.interceptors.request.use((config) => {
const headers = new AxiosHeaders(config.headers);
headers.set('Authorization', `Bearer ${accessToken}`);

// If a base URL is provided, override the request URL
// using the given base URL. Otherwise, evaluate to an empty object so
// we can still use the spread operator later on.
const url = config.url;
const urlOverride =
!baseUrl || !url ? {} : { url: url.replace(defaultApiRoot, baseUrl) };
// using the given base URL.
if (baseUrl && config.url) {
config.url = config.url.replace(defaultApiRoot, baseUrl);
}

return {
...config,
headers: {
...config.headers,
common: {
...config.headers.common,
authorization: `Bearer ${accessToken}`,
},
},
...urlOverride,
};
return { ...config, headers };
});
};
3 changes: 1 addition & 2 deletions packages/manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
"@reach/tabs": "^0.10.5",
"@sentry/react": "^7.57.0",
"algoliasearch": "^4.14.3",
"axios": "~0.21.4",
"axios-mock-adapter": "^1.15.0",
"axios": "~1.6.1",
"braintree-web": "^3.92.2",
"chart.js": "~2.9.4",
"chartjs-adapter-luxon": "^0.2.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/manager/src/features/Images/requests.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Axios, { AxiosRequestConfig } from 'axios';
import Axios, { AxiosProgressEvent, AxiosRequestConfig } from 'axios';

const axiosInstance = Axios.create({});

Expand All @@ -8,7 +8,7 @@ const headerContentType = 'application/octet-stream';
export const uploadImageFile = (
signedUrl: string,
file: File,
onUploadProgress: (e: ProgressEvent) => void
onUploadProgress: (e: AxiosProgressEvent) => void
) => {
const CancelToken = Axios.CancelToken;
const source = CancelToken.source();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
defaultState,
pathOrFileName,
} from './reducer';
import { AxiosProgressEvent } from 'axios';

interface Props {
bucketName: string;
Expand Down Expand Up @@ -285,10 +286,10 @@ export const ObjectUploader = React.memo((props: Props) => {
export const onUploadProgressFactory = (
dispatch: (value: ObjectUploaderAction) => void,
fileName: string
) => (progressEvent: ProgressEvent) => {
) => (progressEvent: AxiosProgressEvent) => {
dispatch({
data: {
percentComplete: (progressEvent.loaded / progressEvent.total) * 100,
percentComplete: (progressEvent.loaded / (progressEvent.total ?? 1)) * 100,
},
filesToUpdate: [fileName],
type: 'UPDATE_FILES',
Expand Down
4 changes: 2 additions & 2 deletions packages/manager/src/features/ObjectStorage/requests.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import Axios, { AxiosRequestConfig } from 'axios';
import Axios, { AxiosProgressEvent, AxiosRequestConfig } from 'axios';

const axiosInstance = Axios.create({});

export const uploadObject = (
signedUrl: string,
file: File,
onUploadProgress: (e: ProgressEvent) => void
onUploadProgress: (e: AxiosProgressEvent) => void
) => {
const config: AxiosRequestConfig = {
data: file,
Expand Down
46 changes: 25 additions & 21 deletions packages/manager/src/request.test.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,51 @@
import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import { AxiosError, AxiosHeaders, AxiosResponse } from 'axios';

import { handleStartSession } from 'src/store/authentication/authentication.actions';

import { profileFactory } from './factories';
import { queryClientFactory } from './queries/base';
import { getURL, handleError, injectEuuidToProfile } from './request';
import {
LinodeError,
getURL,
handleError,
injectEuuidToProfile,
} from './request';
import { storeFactory } from './store';

import type { APIError } from '@linode/api-v4';

const store = storeFactory(queryClientFactory());

const baseErrorConfig: AxiosRequestConfig = {
headers: {},
method: 'POST',
};
const baseError = {
config: baseErrorConfig,
const mockAxiosError = {
isAxiosError: true,
message: 'helloworld',
name: 'requestName',
response: {
config: {},
data: [],
config: {
headers: new AxiosHeaders({}),
},
data: { errors: [{ reason: 'This is a Linode error.' }] },
headers: {},
statusText: '',
},
};
const baseErrorWithJson = {
...baseError,
toJSON: () => baseError,
...mockAxiosError,
toJSON: () => mockAxiosError,
};

const error400: AxiosError = {
const error400: AxiosError<LinodeError> = {
...baseErrorWithJson,
response: {
...baseError.response,
...mockAxiosError.response,
status: 400,
},
};

const error401: AxiosError = {
const error401: AxiosError<LinodeError> = {
...baseErrorWithJson,
response: {
...baseError.response,
...mockAxiosError.response,
status: 401,
},
};
Expand All @@ -67,8 +71,8 @@ describe('Expiring Tokens', () => {
scopes: null,
token: null,
});
expireToken.catch((e: AxiosError) =>
expect(e[0].reason).toMatch(/unexpected error/)
expireToken.catch((e: APIError[]) =>
expect(e[0].reason).toMatch(mockAxiosError.response.data.errors[0].reason)
);
});

Expand All @@ -92,8 +96,8 @@ describe('Expiring Tokens', () => {
scopes: '*',
token: 'helloworld',
});
expireToken.catch((e: AxiosError) =>
expect(e[0].reason).toMatch(/unexpected error/)
expireToken.catch((e: APIError[]) =>
expect(e[0].reason).toMatch(mockAxiosError.response.data.errors[0].reason)
);
});
});
Expand All @@ -116,7 +120,7 @@ describe('getURL', () => {
describe('injectEuuidToProfile', () => {
const profile = profileFactory.build();
const response: Partial<AxiosResponse> = {
config: { method: 'get', url: '/profile' },
config: { headers: new AxiosHeaders(), method: 'get', url: '/profile' },
data: profile,
headers: { 'x-customer-uuid': '1234' },
status: 200,
Expand Down
33 changes: 23 additions & 10 deletions packages/manager/src/request.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { baseRequest } from '@linode/api-v4/lib/request';
import { APIError } from '@linode/api-v4/lib/types';
import { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
import {
AxiosError,
AxiosHeaders,
AxiosRequestConfig,
AxiosResponse,
} from 'axios';
import * as React from 'react';

import { AccountActivationError } from 'src/components/AccountActivation';
Expand All @@ -25,7 +30,13 @@ const handleSuccess: <T extends AxiosResponse<any>>(response: T) => T | T = (
return response;
};

export const handleError = (error: AxiosError, store: ApplicationStore) => {
// All errors returned by the actual Linode API are in this shape.
export type LinodeError = { errors: APIError[] };

export const handleError = (
error: AxiosError<LinodeError>,
store: ApplicationStore
) => {
if (error.response && error.response.status === 401) {
/**
* this will blow out redux state and the componentDidUpdate in the
Expand All @@ -34,8 +45,8 @@ export const handleError = (error: AxiosError, store: ApplicationStore) => {
store.dispatch(handleLogout());
}

const config = error.response?.config ?? {};
const url = config.url ?? '';
const config = error.response?.config;
const url = config?.url ?? '';
const status: number = error.response?.status ?? 0;
const errors: APIError[] = error.response?.data?.errors ?? [
{ reason: DEFAULT_ERROR_MESSAGE },
Expand Down Expand Up @@ -186,12 +197,13 @@ export const setupInterceptors = (store: ApplicationStore) => {

const url = getURL(config);

const headers = new AxiosHeaders(config.headers);

headers.setAuthorization(token);

return {
...config,
headers: {
...config.headers,
...(token && { Authorization: `${token}` }),
},
headers,
url,
};
});
Expand All @@ -202,8 +214,9 @@ export const setupInterceptors = (store: ApplicationStore) => {
* displays a Maintenance view if the API is in Maintenance mode
Also rejects non-error responses if the API is in Maintenance mode
*/
baseRequest.interceptors.response.use(handleSuccess, (error: AxiosError) =>
handleError(error, store)
baseRequest.interceptors.response.use(
handleSuccess,
(error: AxiosError<LinodeError>) => handleError(error, store)
);

baseRequest.interceptors.response.use(injectEuuidToProfile);
Expand Down
2 changes: 1 addition & 1 deletion packages/validation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"eslint-plugin-sonarjs": "^0.5.0",
"lint-staged": "^13.2.2",
"prettier": "~2.2.1",
"tsup": "^6.7.0"
"tsup": "^7.2.0"
},
"keywords": [
"linode",
Expand Down
Loading