Skip to content

Commit

Permalink
Merge pull request #362 from contentful/feat/bump-axios-to-1.x
Browse files Browse the repository at this point in the history
BREAKING CHANGE: bump axios to 1.x
  • Loading branch information
marcolink authored Jul 17, 2023
2 parents f7a56cd + db52a08 commit b746440
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 34 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"@types/qs": "^6.9.5",
"@typescript-eslint/eslint-plugin": "^5.11.0",
"@typescript-eslint/parser": "^5.11.0",
"axios": "^0.26.0",
"axios": "^1.4.0",
"axios-mock-adapter": "^1.20.0",
"babel-eslint": "^10.1.0",
"bundlesize": "^0.18.1",
Expand Down
5 changes: 1 addition & 4 deletions src/async-token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ import type { AxiosInstance } from './types'
export default function asyncToken(instance: AxiosInstance, getToken: () => Promise<string>): void {
instance.interceptors.request.use(function (config) {
return getToken().then((accessToken) => {
config.headers = {
...config.headers,
Authorization: `Bearer ${accessToken}`,
}
config.headers.set('Authorization', `Bearer ${accessToken}`)
return config
})
})
Expand Down
19 changes: 11 additions & 8 deletions src/create-http-client.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { AxiosRequestHeaders } from 'axios'
import type { AxiosRequestHeaders, AxiosStatic } from 'axios'
import copy from 'fast-copy'
import qs from 'qs'
import type { AxiosStatic } from 'axios'
import rateLimitThrottle from './rate-limit-throttle'
import type { AxiosInstance, CreateHttpClientParams } from './types'
import asyncToken from './async-token'

import rateLimitRetry from './rate-limit'
import asyncToken from './async-token'
import rateLimitThrottle from './rate-limit-throttle'
import type { AxiosInstance, CreateHttpClientParams, DefaultOptions } from './types'

// Matches 'sub.host:port' or 'host:port' and extracts hostname and port
// Also enforces toplevel domain specified, no spaces and no protocol
const HOST_REGEX = /^(?!\w+:\/\/)([^\s:]+\.?[^\s:]+)(?::(\d+))?(?!:)$/

/**
* Create pre configured axios instance
* Create pre-configured axios instance
* @private
* @param {AxiosStatic} axios - Axios library
* @param {CreateHttpClientParams} options - Initialization parameters for the HTTP client
Expand Down Expand Up @@ -85,13 +84,17 @@ export default function createHttpClient(
config.headers.Authorization = 'Bearer ' + config.accessToken
}

const axiosOptions = {
const axiosOptions: DefaultOptions = {
// Axios
baseURL,
headers: config.headers,
httpAgent: config.httpAgent,
httpsAgent: config.httpsAgent,
paramsSerializer: qs.stringify,
paramsSerializer: {
serialize: (params) => {
return qs.stringify(params, { arrayFormat: 'repeat' })
},
},
proxy: config.proxy,
timeout: config.timeout,
adapter: config.adapter,
Expand Down
24 changes: 7 additions & 17 deletions src/error-handler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import isPlainObject from 'lodash.isplainobject'
import { AxiosError } from 'axios'
import type { AxiosError } from 'axios'
import type { ContentfulErrorData } from './types'

/**
* Handles errors received from the server. Parses the error into a more useful
Expand All @@ -9,7 +10,7 @@ import { AxiosError } from 'axios'
* and the expected error codes.
* @private
*/
export default function errorHandler(errorResponse: AxiosError): never {
export default function errorHandler(errorResponse: AxiosError<ContentfulErrorData>): never {
const { config, response } = errorResponse
let errorName

Expand All @@ -25,29 +26,22 @@ export default function errorHandler(errorResponse: AxiosError): never {

const data = response?.data

const errorData: {
status?: number
statusText?: string
requestId?: string
message: string
details: Record<string, unknown>
request?: Record<string, unknown>
} = {
const errorData: ContentfulErrorData = {
status: response?.status,
statusText: response?.statusText,
message: '',
details: {},
}

if (isPlainObject(config)) {
if (config && isPlainObject(config)) {
errorData.request = {
url: config.url,
headers: config.headers,
method: config.method,
payloadData: config.data,
}
}
if (data && isPlainObject(data)) {
if (data && typeof data === 'object') {
if ('requestId' in data) {
errorData.requestId = data.requestId || 'UNKNOWN'
}
Expand All @@ -57,11 +51,7 @@ export default function errorHandler(errorResponse: AxiosError): never {
if ('details' in data) {
errorData.details = data.details || {}
}
if ('sys' in data) {
if ('id' in data.sys) {
errorName = data.sys.id
}
}
errorName = data.sys?.id
}

const error = new Error()
Expand Down
18 changes: 15 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { AxiosRequestHeaders } from 'axios'
import { AxiosRequestHeaders, InternalAxiosRequestConfig } from 'axios'

import type {
AxiosInstance as OriginalAxiosInstance,
AxiosRequestConfig,
AxiosResponse,
} from 'axios'

type DefaultOptions = AxiosRequestConfig & {
export type DefaultOptions = AxiosRequestConfig & {
logHandler: (level: string, data?: Error | string) => void
responseLogger?: (response: AxiosResponse<any> | Error) => unknown
requestLogger?: (request: AxiosRequestConfig | Error) => unknown
Expand Down Expand Up @@ -53,7 +53,9 @@ export type CreateHttpClientParams = {
responseLogger?: DefaultOptions['responseLogger']

/** Request interceptor */
onBeforeRequest?: (value: AxiosRequestConfig) => AxiosRequestConfig | Promise<AxiosRequestConfig>
onBeforeRequest?: (
value: InternalAxiosRequestConfig
) => InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig>

/** Error handler */
onError?: (error: any) => any
Expand Down Expand Up @@ -114,3 +116,13 @@ export type CreateHttpClientParams = {
*/
attempt?: number
}

export type ContentfulErrorData = {
status?: number
statusText?: string
requestId?: string
message: string
details: Record<string, unknown>
request?: Record<string, unknown>
sys?: { id?: string }
}
2 changes: 1 addition & 1 deletion test/unit/rate-limit-test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ it('no retry when automatic handling flag is disabled', async () => {
await client.get('/rate-limit-me')
} catch (error: any) {
expect(error.response.status).toEqual(500)
expect(error.response.headers['x-contentful-request-id']).toEqual(3)
expect(error.response.headers['x-contentful-request-id']).toEqual('3')
expect(error.response.data).toEqual('Mocked 500 Error')
expect(logHandlerStub).toHaveBeenCalledTimes(0)
expect(error.message).toEqual('Request failed with status code 500')
Expand Down

0 comments on commit b746440

Please sign in to comment.