From 27f342f536f90f9d83b8de36103bd29046dee1f3 Mon Sep 17 00:00:00 2001 From: Vitalii Smolinskyi <46049489+VBeytok@users.noreply.github.com> Date: Tue, 21 Nov 2023 09:12:44 +0200 Subject: [PATCH] fix: CrowdinValidationError and handle single error (#341) --- src/core/index.ts | 31 +++++++++++++++++++++---------- tests/core/error-handling.test.ts | 12 ++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/core/index.ts b/src/core/index.ts index d589abc1e..d1d839a17 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -133,24 +133,32 @@ export class CrowdinError extends Error { */ export class CrowdinValidationError extends CrowdinError { public validationCodes: { key: string; codes: string[] }[]; - constructor(messsage: string, validationCodes: { key: string; codes: string[] }[]) { - super(messsage, 400); + constructor(message: string, validationCodes: { key: string; codes: string[] }[]) { + super(message, 400); this.validationCodes = validationCodes; } } +function isAxiosError(error: any): error is AxiosError { + return error instanceof AxiosError || !!error.response?.data; +} + /** * @internal */ export function handleHttpClientError(error: HttpClientError): never { - const crowdinResponseErrors = - error instanceof AxiosError - ? error.response?.data?.errors - : error instanceof FetchClientJsonPayloadError - ? error.jsonPayload && typeof error.jsonPayload === 'object' && 'errors' in error.jsonPayload - ? error.jsonPayload.errors - : null - : null; + let crowdinResponseErrors: any = null; + + if (isAxiosError(error)) { + crowdinResponseErrors = (error.response?.data as any)?.errors || (error.response?.data as any)?.error; + } else if (error instanceof FetchClientJsonPayloadError) { + crowdinResponseErrors = + error.jsonPayload && + typeof error.jsonPayload === 'object' && + ('errors' in error.jsonPayload || 'error' in error.jsonPayload) + ? error.jsonPayload.errors || error.jsonPayload.error + : null; + } if (Array.isArray(crowdinResponseErrors)) { const validationCodes: { key: string; codes: string[] }[] = []; @@ -172,7 +180,10 @@ export function handleHttpClientError(error: HttpClientError): never { }); const message = validationMessages.length === 0 ? 'Validation error' : validationMessages.join(', '); throw new CrowdinValidationError(message, validationCodes); + } else if (crowdinResponseErrors?.message && crowdinResponseErrors?.code) { + throw new CrowdinError(crowdinResponseErrors.message, crowdinResponseErrors.code); } + if (error instanceof Error) { const code = error instanceof AxiosError && error.response?.status diff --git a/tests/core/error-handling.test.ts b/tests/core/error-handling.test.ts index d5b27c747..d1ee1984d 100644 --- a/tests/core/error-handling.test.ts +++ b/tests/core/error-handling.test.ts @@ -18,6 +18,13 @@ const genericCrowdinErrorPayload = { ], }; +const genericCrowdinSingleErrorPayload = { + error: { + message: 'test_errors_error_msg', + code: 403, + }, +}; + const stringBatchOperationsErrorPayload = { errors: [ { @@ -88,6 +95,11 @@ describe('core http error handling', () => { } }); + it('should extract Crowdin API single message with axios client', async () => { + const error = createAxiosError(genericCrowdinSingleErrorPayload); + expect(() => handleHttpClientError(error)).toThrowError(genericCrowdinSingleErrorPayload.error.message); + }); + it('should print full error message for stringBatchOperations axios errors', async () => { const error = createAxiosError(stringBatchOperationsErrorPayload); expect(() => handleHttpClientError(error)).toThrowError(