Skip to content

Commit

Permalink
♻️(frontend) improve general error catching
Browse files Browse the repository at this point in the history
- change parseAPIError to make it reusable on all
requests
- update components depending on it
  • Loading branch information
daproclaima committed Sep 12, 2024
1 parent db23941 commit df0ecd6
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 392 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
parseAPIError,
parseAPIErrorCause,
parseServerAPIError,
} from '../parseAPIErrorV2';
} from '../parseAPIError';

describe('parseAPIError', () => {
const handleErrorMock = jest.fn();
Expand Down
174 changes: 0 additions & 174 deletions src/frontend/apps/desk/src/api/__tests__/parseAPIError.test.tsx

This file was deleted.

152 changes: 78 additions & 74 deletions src/frontend/apps/desk/src/api/parseAPIError.ts
Original file line number Diff line number Diff line change
@@ -1,102 +1,106 @@
import { APIError } from '@/api/index';

type ErrorParams = {
[fieldName: string]: {
causes: string[];
causeShown?: string;
handleError: () => void;
};
};
type ErrorCallback = () => void;

type ServerErrorParams = {
defaultMessage: string;
handleError?: () => void;
};
// Type for the error tuple format [causes, message, handleError]
type ErrorTuple = [string[], string, ErrorCallback | undefined];

// Server error tuple [defaultMessage, handleError]
type ServerErrorTuple = [string, ErrorCallback | undefined];

export type parseAPIErrorParams = {
error: APIError | null;
errorParams?: ErrorParams;
serverErrorParams: ServerErrorParams;
};
/**
* @function
* @description created to centralize APIError handling to treat already discovered errors and treat error type 500
* with a default behaviour
* @param error
* @param errorParams
* @param serverErrorParams
* @todo worth refactor to make it easier to use, like const causes = parseAPIError(
* error,
* [
* [['error1', 'error2'], 'message', callback1],
* [['error3', 'error4'], 'message', callback2],
* ],
* [['default error 500 message'], callbackErrorServer]
* )
* @function parseAPIError
* @description function to centralize APIError handling to treat discovered errors
* and error type 500 with default behavior using a simplified tuple structure.
* @param error - APIError object
* @param errorParams - Array of tuples: each contains an array of causes, a message, and an optional callback function.
* @param serverErrorParams - A tuple for server error handling: [defaultMessage, handleError]
* @returns Array of error messages or undefined
*/

export const parseAPIError = ({
error,
errorParams,
serverErrorParams,
}: parseAPIErrorParams) => {
if (!error || !serverErrorParams?.defaultMessage) {
}: {
error: APIError | null;
errorParams?: ErrorTuple[];
serverErrorParams?: ServerErrorTuple;
}): string[] | undefined => {
if (!error) {
return;
}

let causes: string[] =
// Parse known error causes using the tuple structure
const errorCauses =
error.cause?.length && errorParams
? parseAPIErrorCause({ causes: error.cause, errorParams })
: [];
? parseAPIErrorCause(error, errorParams)
: undefined;

// Check if it's a server error (500) and handle that case
const serverErrorCause =
(error?.status === 500 || !error?.status) && serverErrorParams
? parseServerAPIError(serverErrorParams)
: undefined;

if (error?.status === 500 || !error?.status) {
causes = parseServerAPIError({ causes, serverErrorParams });
// Combine the causes and return
const causes: string[] = errorCauses ? [...errorCauses] : [];
if (serverErrorCause) {
causes.unshift(serverErrorCause);
}

return causes;
return causes.length ? causes : undefined;
};

export const parseAPIErrorCause = ({
causes,
errorParams,
}: {
causes: string[];
errorParams: ErrorParams;
}): string[] =>
causes.reduce((arrayCauses, cause) => {
const foundErrorParams = Object.values(errorParams).find((params) =>
params.causes.find((knownCause) =>
new RegExp(knownCause, 'i').test(cause),
),
);
/**
* @function parseAPIErrorCause
* @description Processes known API error causes using the tuple structure.
* @param error - APIError object
* @param errorParams - Array of tuples: each contains an array of causes, a message, and an optional callback function.
* @returns Array of error messages
*/
export const parseAPIErrorCause = (
error: APIError,
errorParams: ErrorTuple[],
): string[] | undefined => {
if (!error.cause) {
return;
}

if (!foundErrorParams) {
arrayCauses.push(cause);
}
return error.cause.reduce((causes: string[], cause: string) => {
// Find the matching error tuple
const matchedError = errorParams.find(([errorCauses]) =>
errorCauses.some((knownCause) => new RegExp(knownCause, 'i').test(cause)),
);

if (foundErrorParams?.causeShown) {
arrayCauses.push(foundErrorParams.causeShown);
}
if (matchedError) {
const [, message, handleError] = matchedError;
causes.push(message);

if (typeof foundErrorParams?.handleError === 'function') {
foundErrorParams.handleError();
if (handleError) {
handleError();
}
} else {
// If no match is found, add the original cause
causes.push(cause);
}

return arrayCauses;
}, [] as string[]);

export const parseServerAPIError = ({
causes,
serverErrorParams,
}: {
causes: string[];
serverErrorParams: ServerErrorParams;
}): string[] => {
causes.unshift(serverErrorParams.defaultMessage);
return causes;
}, []);
};

if (typeof serverErrorParams?.handleError === 'function') {
serverErrorParams.handleError();
/**
* @function parseServerAPIError
* @description Handles server errors (500) and adds the default message.
* @param serverErrorParams - Tuple [defaultMessage, handleError]
* @returns Server error message
*/
export const parseServerAPIError = ([
defaultMessage,
handleError,
]: ServerErrorTuple): string => {
if (handleError) {
handleError();
}

return causes;
return defaultMessage;
};
Loading

0 comments on commit df0ecd6

Please sign in to comment.