From e60563fb540c04d9ba751fea69c1fc0f1de598b5 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 22 Jul 2020 14:22:03 +0530 Subject: consistent error handling for HTTP request (and some other things) --- src/operations/errors.ts | 61 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 16 deletions(-) (limited to 'src/operations/errors.ts') diff --git a/src/operations/errors.ts b/src/operations/errors.ts index 01a8283cb..198d3f8c5 100644 --- a/src/operations/errors.ts +++ b/src/operations/errors.ts @@ -23,14 +23,15 @@ /** * Imports. */ -import { OperationError } from "../types/walletTypes"; +import { OperationErrorDetails } from "../types/walletTypes"; +import { TalerErrorCode } from "../TalerErrorCode"; /** * This exception is there to let the caller know that an error happened, * but the error has already been reported by writing it to the database. */ export class OperationFailedAndReportedError extends Error { - constructor(public operationError: OperationError) { + constructor(public operationError: OperationErrorDetails) { super(operationError.message); // Set the prototype explicitly. @@ -43,7 +44,15 @@ export class OperationFailedAndReportedError extends Error { * responsible for recording the failure in the database. */ export class OperationFailedError extends Error { - constructor(public operationError: OperationError) { + static fromCode( + ec: TalerErrorCode, + message: string, + details: Record, + ): OperationFailedError { + return new OperationFailedError(makeErrorDetails(ec, message, details)); + } + + constructor(public operationError: OperationErrorDetails) { super(operationError.message); // Set the prototype explicitly. @@ -51,6 +60,19 @@ export class OperationFailedError extends Error { } } +export function makeErrorDetails( + ec: TalerErrorCode, + message: string, + details: Record, +): OperationErrorDetails { + return { + talerErrorCode: ec, + talerErrorHint: `Error: ${TalerErrorCode[ec]}`, + details: details, + message, + }; +} + /** * Run an operation and call the onOpError callback * when there was an exception or operation error that must be reported. @@ -58,7 +80,7 @@ export class OperationFailedError extends Error { */ export async function guardOperationException( op: () => Promise, - onOpError: (e: OperationError) => Promise, + onOpError: (e: OperationErrorDetails) => Promise, ): Promise { try { return await op(); @@ -71,21 +93,28 @@ export async function guardOperationException( throw new OperationFailedAndReportedError(e.operationError); } if (e instanceof Error) { - const opErr = { - type: "exception", - message: e.message, - details: {}, - }; + const opErr = makeErrorDetails( + TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, + `unexpected exception (message: ${e.message})`, + {}, + ); await onOpError(opErr); throw new OperationFailedAndReportedError(opErr); } - const opErr = { - type: "exception", - message: "unexpected exception thrown", - details: { - value: e.toString(), - }, - }; + // Something was thrown that is not even an exception! + // Try to stringify it. + let excString: string; + try { + excString = e.toString(); + } catch (e) { + // Something went horribly wrong. + excString = "can't stringify exception"; + } + const opErr = makeErrorDetails( + TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, + `unexpected exception (not an exception, ${excString})`, + {}, + ); await onOpError(opErr); throw new OperationFailedAndReportedError(opErr); } -- cgit v1.2.3