Skip to content

Commit

Permalink
PP-11682 Update axios client with validateStatus config
Browse files Browse the repository at this point in the history
- Updated the Axios config so that the `validateStatus` option can be
  toggled.
  - Default - everything that is not 2xx will throw an exception.
    - E.g. 404 will throw an exception.
  - Now added the  `acceptAllStatusCodes` option:
    - If this is set to `true` then all status codes are considered
      a succes and won't throw an exception.
    - E.g. 404 will NOT throw an exception.
  - Updated the retry behaviour when a `get` request and the error
    returned is `ECONNRESET`:
    - When  acceptAllStatusCodes=false
      - Will retry 3 times and call the failure callback method
    - When  acceptAllStatusCodes=true
      - Will retry 3 times and call the success callback method
  - Pass reason and message in errorContext
- Bump version to v6

Co-authored-by: Iqbal Ahmed <iqbal.ahmed@digital.cabinet-office.gov.uk>
Co-authored-by: Hugo Jeffreys <hugo.jeffreys@digital.cabinet-office.gov.uk>
Co-authored-by: Marco Tranchino <marco.tranchino@digital.cabinet-office.gov.uk>
  • Loading branch information
3 people committed Jun 11, 2024
1 parent f4e17f3 commit 80576aa
Show file tree
Hide file tree
Showing 4 changed files with 522 additions and 66 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@govuk-pay/pay-js-commons",
"version": "5.0.3",
"version": "6.0.0",
"description": "Reusable js scripts for GOV.UK Pay Node.js projects",
"engines": {
"node": "^18.17.1"
Expand Down
72 changes: 54 additions & 18 deletions src/utils/axios-base-client/axios-base-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Client {
* Configure the client. Should only be called once.
*/
configure (baseURL, options) {
this._axios = axios.create({
const axiosConfigOptions = {
baseURL,
timeout: 60 * 1000,
maxContentLength: 50 * 1000 * 1000,
Expand All @@ -27,9 +27,15 @@ class Client {
}),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
Accept: 'application/json'
}
})
}

if (options.acceptAllStatusCodes) {
axiosConfigOptions.validateStatus = (status) => status
}

this._axios = axios.create(axiosConfigOptions)

this._axios.interceptors.request.use(config => {
const requestContext = {
Expand All @@ -56,7 +62,7 @@ class Client {
}
})

this._axios.interceptors.response.use((response) => {
this._axios.interceptors.response.use(async (response) => {
const responseContext = {
service: this._app,
responseTime: Date.now() - (response.config).metadata.start,
Expand All @@ -65,36 +71,64 @@ class Client {
status: response.status,
url: response.config.url,
description: response.config.description,
additionalLoggingFields: response.config.additionalLoggingFields
additionalLoggingFields: response.config.additionalLoggingFields,
code: response.status,
errorIdentifier: response.data && response.data.error_identifier ? response.data.error_identifier : null,
reason: response.data && response.data.reason ? response.data.reason : null,
message: response.data && response.data.message ? response.data.message : null
}

if (response.config.method === 'get' && response.data.code === 'ECONNRESET') {
const retryCount = response.config.retryCount || 0

if (retryCount < 2) {
response.config.retryCount = retryCount + 1

if (options.onSuccessResponse) {
options.onSuccessResponse(responseContext)
}

await new Promise(resolve => setTimeout(resolve, 500))
return this._axios(response.config)
}
}

if (options.onSuccessResponse) {
options.onSuccessResponse(responseContext)
}

return response
}, async (error) => {
const config = error.config || {}
let errors = error.response.data && (error.response.data.message || error.response.data.errors)
if (errors && Array.isArray(errors)) {
errors = errors.join(', ')

let message

if (error.response && error.response.data && error.response.data.errors) {
message = error.response.data.errors.join(', ')
} else if (error.response && error.response.data && error.response.data.message) {
message = error.response.data.message
} else {
message = 'Unknown error'
}

const errorContext = {
service: this._app,
responseTime: Date.now() - (config.metadata && config.metadata.start),
method: config.method,
params: config.params,
status: error.response && error.response.status,
status: (error.response && error.response.status) || error.status,
url: config.url,
code: (error.response && error.response.status) || error.code,
errorIdentifier: error.response && error.response.data && error.response.data.error_identifier,
reason: error.response && error.response.data && error.response.data.reason,
message: errors || error.response.data || 'Unknown error',
params: config.params,
code: (error.response && error.response.data && error.response.data.code) || error.code,
message,
reason: (error.response && error.response.data && error.response.data.reason) || 'Unknown reason',
description: config.description,
additionalLoggingFields: config.additionalLoggingFields
additionalLoggingFields: config.additionalLoggingFields,
errorIdentifier: (error.response && error.response.data && error.response.data.error_identifier)
}

// TODO: could use axios-retry to achieve this if desired
// Retry ECONNRESET errors for GET requests 3 times in total
if (config.method === 'get' && error.code === 'ECONNRESET') {
const errorCode = error.response && error.response.data && error.response.data.code

if (config.method === 'get' && errorCode === 'ECONNRESET') {
const retryCount = config.retryCount || 0
if (retryCount < 2) {
config.retryCount = retryCount + 1
Expand All @@ -106,9 +140,11 @@ class Client {
return this._axios(config)
}
}

if (options.onFailureResponse) {
options.onFailureResponse(errorContext)
}

throw new RESTClientError(errorContext.message, errorContext.service, errorContext.status, errorContext.errorIdentifier, errorContext.reason)
})
}
Expand Down
Loading

0 comments on commit 80576aa

Please sign in to comment.