Skip to content
Open
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
11 changes: 5 additions & 6 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,12 @@ export function canRaiseHTTPError(
try {
return await descriptor.value.apply(this, args);
} catch (exc: any) {
if (axios.isAxiosError(exc) && exc.response) {
const errorData = exc.response.data as Record<string, any>;
const ErrorKlass = getErrorClass(errorData.error.type);
throw new ErrorKlass(errorData.error);
} else {
throw exc;
const apiError = axios.isAxiosError(exc) ? exc.response?.data?.error : undefined;
if (apiError && typeof apiError === 'object' && typeof apiError.type === 'string') {
const ErrorKlass = getErrorClass(apiError.type);
throw new ErrorKlass(apiError);
}
throw exc;
}
};

Expand Down
48 changes: 47 additions & 1 deletion src/spec/utils/canRaiseHTTPError.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import test from 'ava';

import { FintocError } from '../../lib/errors';
import { FintocError, InvalidRequestError } from '../../lib/errors';
import { canRaiseHTTPError } from '../../lib/utils';

class Errors {
Expand Down Expand Up @@ -28,6 +28,20 @@ class Errors {
throwGenericError() {
throw new Error();
}

@canRaiseHTTPError
throwAxiosError(error: Error) {
throw error;
}
}

function buildAxiosError(data: unknown) {
const error = new Error('Request failed with status code 400');
// @ts-ignore: property does not exist
error.isAxiosError = true;
// @ts-ignore: property does not exist
error.response = { status: 400, data };
return error;
}

test.beforeEach((t) => {
Expand All @@ -53,3 +67,35 @@ test('"canRaiseHTTPError" generic error', async (t) => {

await t.throwsAsync(ctx.errors.throwGenericError, { instanceOf: Error });
});

test('"canRaiseHTTPError" typed API error body', async (t) => {
const ctx: any = t.context;
const original = buildAxiosError({
error: { type: 'invalid_request_error', message: 'Bad param' },
});

await t.throwsAsync(() => ctx.errors.throwAxiosError(original), {
instanceOf: InvalidRequestError,
});
});

const bodiesWithoutErrorType: [string, unknown][] = [
['string body', '400 Bad Request'],
['HTML body', '<html><body><h1>400 Bad Request</h1></body></html>'],
['empty object body', {}],
['object body without error.type', { error: {} }],
['non-object error', { error: 'Bad Request' }],
['undefined body', undefined],
['null body', null],
];

bodiesWithoutErrorType.forEach(([description, data]) => {
test(`"canRaiseHTTPError" re-throws the original error with ${description}`, async (t) => {
const ctx: any = t.context;
const original = buildAxiosError(data);

const thrown = await t.throwsAsync(() => ctx.errors.throwAxiosError(original));

t.is(thrown, original);
});
});