Skip to content

Commit

Permalink
Mm/prc 7963 client ex status code override (#58)
Browse files Browse the repository at this point in the history
Release 5.4.0
  • Loading branch information
mmaruniak authored Apr 24, 2024
1 parent bcfd990 commit b97e3d0
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 11 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)

## [5.4.0] - 2024-02-08

### Added

HttpClient options now accept `clientExceptionStatusCodeMapOverride` which can be used to override the default HTTP error status code mapping. This is useful e.g. when a dependent service is not following REST-ful best practices and e.g. returns a 403 when there's an intermittent network error communicating with the authorization service

## [5.3.2] - 2024-02-08

### Fixed

Error details of external HTTP error resposes are propagated correctly
Error details of external HTTP error responses are propagated correctly

## [5.3.1] - 2023-10-25

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lambda-essentials-ts",
"version": "5.3.2",
"version": "5.4.0",
"description": "A selection of the finest modules supporting authorization, API routing, error handling, logging and sending HTTP requests.",
"main": "lib/index.js",
"private": false,
Expand Down
22 changes: 17 additions & 5 deletions src/exceptions/clientException.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,33 @@ export class ClientException extends Exception {
422: 422,
};

constructor(serviceName: string, originalStatusCode?: number, details?: any) {
constructor(
serviceName: string,
originalStatusCode?: number,
details?: any,
statusCodeMapOverride?: Record<number, number>,
) {
super(
`Dependent service "${serviceName}" returned error`,
ClientException.convertStatusCode(originalStatusCode),
ClientException.convertStatusCode(originalStatusCode, statusCodeMapOverride),
details,
);
this.serviceName = serviceName;
this.originalStatusCode = originalStatusCode;
}

private static convertStatusCode(originalStatusCode?: number) {
private static convertStatusCode(
originalStatusCode?: number,
statusCodeMapOverride?: Record<number, number>,
) {
let statusCode = 503;
const statusCodeMap = {
...ClientException.statusCodeMap,
...(statusCodeMapOverride || {}),
};

if (originalStatusCode && this.statusCodeMap[originalStatusCode]) {
statusCode = this.statusCodeMap[originalStatusCode];
if (originalStatusCode && statusCodeMap[originalStatusCode]) {
statusCode = statusCodeMap[originalStatusCode];
}

return statusCode;
Expand Down
14 changes: 12 additions & 2 deletions src/httpClient/httpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ export default class HttpClient {
private readonly enableCache: boolean;

private readonly timeout?: number;


private readonly clientExceptionStatusCodeMapOverride?: Record<number, number>;

/**
* Create a new Instance of the HttpClient
*/
Expand All @@ -57,6 +59,7 @@ export default class HttpClient {
this.enableCache = options?.enableCache ?? false;
this.enableRetry = options?.enableRetry ?? false;
this.timeout = options?.timeout;
this.clientExceptionStatusCodeMapOverride = options?.clientExceptionStatusCodeMapOverride;
this.client =
options?.client ??
axios.create({
Expand Down Expand Up @@ -103,7 +106,7 @@ export default class HttpClient {
if (this.timeout) {
this.client.defaults.timeout = this.timeout;
}

this.client.interceptors.request.use(
(config) => {
if (this.logOptions.enabledLogs.includes(HttpLogType.requests)) {
Expand Down Expand Up @@ -135,6 +138,7 @@ export default class HttpClient {
hostname,
serializedAxiosError?.status,
serializedAxiosError?.details,
this.clientExceptionStatusCodeMapOverride,
);
},
);
Expand Down Expand Up @@ -183,6 +187,7 @@ export default class HttpClient {
hostname,
serializedAxiosError?.status,
serializedAxiosError?.details,
this.clientExceptionStatusCodeMapOverride,
);
},
);
Expand Down Expand Up @@ -360,6 +365,11 @@ export interface HttpClientOptions {
* @link https://github.com/axios/axios/blob/main/README.md#request-config
*/
timeout?: number;
/**
* Override the default mapping of status code when wrapping error responses returned by dependencies into ClientException.
* This is useful, when dependent services return incorrect status codes than then drive incorrect behavior upstream (e.g. 403 instead of 503)
*/
clientExceptionStatusCodeMapOverride?: Record<number, number>;
}

/**
Expand Down
31 changes: 29 additions & 2 deletions tests/exceptions/clientException.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ interface AxiosErrorTestData {
}

describe('ClientException', () => {
describe('converts Axios errors', () => {
const testServiceName = 'test-service-name';
const testServiceName = 'test-service-name';

describe('converts Axios errors', () => {
const createError = (status: number): SerializedAxiosError => ({
status,
details: [],
Expand Down Expand Up @@ -53,4 +53,31 @@ describe('ClientException', () => {
}),
);
});

describe('clientExceptionStatusCodeMapOverride', () => {
test('overrides default client exception status code mapping with clientExceptionStatusCodeMapOverride', async () => {
const expectedStatusCode = 503;
const originalStatusCode = 403;
const axiosError: SerializedAxiosError = {
status: originalStatusCode,
details: [],
};
const clientExceptionStatusCodeMapOverride = {
403: 503,
};

const clientException = new ClientException(
testServiceName,
axiosError.status,
axiosError,
clientExceptionStatusCodeMapOverride,
);

expect(clientException.message).toEqual(
`Dependent service "${testServiceName}" returned error`,
);
expect(clientException.originalStatusCode).toEqual(originalStatusCode);
expect(clientException.statusCode).toEqual(expectedStatusCode);
});
});
});

0 comments on commit b97e3d0

Please sign in to comment.