From cfe7129c4ecaa3057d5e47040f0a9efd8ed0317e Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 7 Apr 2023 18:46:25 -0300 Subject: [PATCH] adding unreadable http response case and removing deprecated fields --- packages/demobank-ui/src/pages/HomePage.tsx | 8 ++ packages/demobank-ui/src/pages/LoginForm.tsx | 8 ++ packages/demobank-ui/src/utils.ts | 8 ++ .../src/Application.tsx | 83 +++++++----- .../src/ApplicationReadyRoutes.tsx | 40 +++--- .../src/InstanceRoutes.tsx | 9 +- .../src/hooks/testing.tsx | 1 + .../src/paths/admin/list/index.tsx | 18 ++- .../src/paths/instance/details/index.tsx | 19 ++- .../src/paths/instance/kyc/list/index.tsx | 19 ++- .../paths/instance/orders/create/index.tsx | 42 +++++-- .../paths/instance/orders/details/index.tsx | 18 ++- .../src/paths/instance/orders/list/index.tsx | 34 ++++- .../paths/instance/products/list/index.tsx | 18 ++- .../paths/instance/products/update/index.tsx | 18 ++- .../paths/instance/reserves/details/index.tsx | 19 ++- .../paths/instance/reserves/list/index.tsx | 18 ++- .../paths/instance/templates/list/index.tsx | 18 ++- .../src/paths/instance/templates/qr/index.tsx | 18 ++- .../paths/instance/templates/update/index.tsx | 18 ++- .../paths/instance/templates/use/index.tsx | 18 ++- .../paths/instance/transfers/list/index.tsx | 19 ++- .../src/paths/instance/update/index.tsx | 18 ++- .../paths/instance/webhooks/list/index.tsx | 18 ++- .../paths/instance/webhooks/update/index.tsx | 18 ++- packages/web-util/src/utils/request.ts | 118 ++++++------------ 26 files changed, 437 insertions(+), 206 deletions(-) diff --git a/packages/demobank-ui/src/pages/HomePage.tsx b/packages/demobank-ui/src/pages/HomePage.tsx index 0a5a61396..d35f4cc6f 100644 --- a/packages/demobank-ui/src/pages/HomePage.tsx +++ b/packages/demobank-ui/src/pages/HomePage.tsx @@ -172,6 +172,14 @@ export function handleNotOkResult( }); break; } + case ErrorType.UNREADABLE: { + notifyError({ + title: i18n.str`Unexpected error.`, + description: `Response from ${result.info?.url} is unreadable, http status: ${result.status}`, + debug: JSON.stringify(result), + }); + break; + } case ErrorType.UNEXPECTED: { notifyError({ title: i18n.str`Unexpected error.`, diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx b/packages/demobank-ui/src/pages/LoginForm.tsx index 7116e724e..0ea001fe2 100644 --- a/packages/demobank-ui/src/pages/LoginForm.tsx +++ b/packages/demobank-ui/src/pages/LoginForm.tsx @@ -160,6 +160,14 @@ export function LoginForm({ onRegister }: { onRegister?: () => void }): VNode { }); break; } + case ErrorType.UNREADABLE: { + saveError({ + title: i18n.str`Unexpected error.`, + description: `Response from ${cause.info?.url} is unreadable, http status: ${cause.status}`, + debug: JSON.stringify(cause), + }); + break; + } default: { saveError({ title: i18n.str`Unexpected error, please report.`, diff --git a/packages/demobank-ui/src/utils.ts b/packages/demobank-ui/src/utils.ts index 0796db65d..af0329555 100644 --- a/packages/demobank-ui/src/utils.ts +++ b/packages/demobank-ui/src/utils.ts @@ -151,6 +151,14 @@ export function buildRequestErrorMessage( }; break; } + case ErrorType.UNREADABLE: { + result = { + title: i18n.str`Unexpected error`, + description: `Response from ${cause.info?.url} is unreadable, status: ${cause.status}`, + debug: JSON.stringify(cause), + }; + break; + } case ErrorType.UNEXPECTED: { result = { title: i18n.str`Unexpected error`, diff --git a/packages/merchant-backoffice-ui/src/Application.tsx b/packages/merchant-backoffice-ui/src/Application.tsx index ed1fc69f3..354212946 100644 --- a/packages/merchant-backoffice-ui/src/Application.tsx +++ b/packages/merchant-backoffice-ui/src/Application.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, TranslationProvider, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -40,6 +41,7 @@ import { ConfigContextProvider } from "./context/config.js"; import { useBackendConfig } from "./hooks/backend.js"; import { strings } from "./i18n/strings.js"; import LoginPage from "./paths/login/index.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export function Application(): VNode { return ( @@ -77,47 +79,63 @@ function ApplicationStatusRoutes(): VNode { ); } - if (result.clientError && result.isUnauthorized) - return ( - - - - - ); - - if (result.clientError && result.isNotfound) - return ( + if (!result.ok) { + if (result.loading) return ; + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) { + return ( + + + + + ); + } + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) { + return ( + + + + + + ); + } + if (result.type === ErrorType.SERVER) { - - - ); - - if (result.serverError) - return ( - - - - - ); - - if (result.loading) return ; - - if (!result.ok) + ; + } + if (result.type === ErrorType.UNREADABLE) { + + + + + ; + } return ( @@ -131,6 +149,7 @@ function ApplicationStatusRoutes(): VNode { ); + } return (
diff --git a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx b/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx index aeb032fd4..1d4c08cd1 100644 --- a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx +++ b/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx @@ -18,7 +18,10 @@ * * @author Sebastian Javier Marchano (sebasjm) */ -import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser"; +import { + ErrorType, + useTranslationContext, +} from "@gnu-taler/web-util/lib/index.browser"; import { createHashHistory } from "history"; import { Fragment, h, VNode } from "preact"; import { Router, Route, route } from "preact-router"; @@ -32,6 +35,7 @@ import { useBackendInstancesTestForAdmin } from "./hooks/backend.js"; import { InstanceRoutes } from "./InstanceRoutes.js"; import LoginPage from "./paths/login/index.js"; import { INSTANCE_ID_LOOKUP } from "./utils/constants.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export function ApplicationReadyRoutes(): VNode { const { i18n } = useTranslationContext(); @@ -48,28 +52,30 @@ export function ApplicationReadyRoutes(): VNode { route("/"); }; - if (result.clientError && result.isUnauthorized) { - return ( - - - - - - ); - } - if (result.loading) return ; let admin = true; let instanceNameByBackendURL; if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) { + return ( + + + + + + ); + } const path = new URL(backendURL).pathname; const match = INSTANCE_ID_LOOKUP.exec(path); if (!match || !match[1]) { diff --git a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx index b911483a7..aae61bfc3 100644 --- a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx +++ b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx @@ -178,8 +178,8 @@ export function InstanceRoutes({ message: i18n.str`The backend reported a problem: HTTP status #${error.status}`, description: i18n.str`Diagnostic from ${error.info?.url} is '${error.message}'`, details: - error.clientError || error.serverError - ? error.error?.detail + error.type === ErrorType.CLIENT || error.type === ErrorType.SERVER + ? error.payload.detail : undefined, type: "ERROR", to, @@ -608,8 +608,9 @@ function AdminInstanceUpdatePage({ message: i18n.str`The backend reported a problem: HTTP status #${error.status}`, description: i18n.str`Diagnostic from ${error.info?.url} is '${error.message}'`, details: - error.clientError || error.serverError - ? error.error?.detail + error.type === ErrorType.CLIENT || + error.type === ErrorType.SERVER + ? error.payload.detail : undefined, type: "ERROR" as const, }; diff --git a/packages/merchant-backoffice-ui/src/hooks/testing.tsx b/packages/merchant-backoffice-ui/src/hooks/testing.tsx index 64e646bb5..67831f8a4 100644 --- a/packages/merchant-backoffice-ui/src/hooks/testing.tsx +++ b/packages/merchant-backoffice-ui/src/hooks/testing.tsx @@ -83,6 +83,7 @@ export class ApiMockEnvironment extends MockEnvironment { status: !mocked ? 200 : mocked.status, url: _url.href, payload: options.data, + options: {}, }, }; } diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx index dd1c1e557..12e5708cb 100644 --- a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -32,6 +33,7 @@ import { MerchantBackend } from "../../../declaration.js"; import { useAdminAPI, useBackendInstances } from "../../../hooks/instance.js"; import { Notification } from "../../../utils/types.js"; import { View } from "./View.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; interface Props { onCreate: () => void; @@ -60,10 +62,20 @@ export default function Instances({ const [notif, setNotif] = useState(undefined); const { i18n } = useTranslationContext(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx index 25d37a5cb..17089c555 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/details/index.tsx @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ -import { HttpError } from "@gnu-taler/web-util/lib/index.browser"; +import { ErrorType, HttpError } from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../components/exception/loading.js"; @@ -22,6 +22,7 @@ import { useInstanceContext } from "../../../context/instance.js"; import { MerchantBackend } from "../../../declaration.js"; import { useInstanceAPI, useInstanceDetails } from "../../../hooks/instance.js"; import { DetailPage } from "./DetailPage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; interface Props { onUnauthorized: () => VNode; @@ -44,10 +45,20 @@ export default function Detail({ const { deleteInstance } = useInstanceAPI(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx index 4b0967bc9..dc74acdb6 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/kyc/list/index.tsx @@ -19,12 +19,13 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpError } from "@gnu-taler/web-util/lib/index.browser"; +import { ErrorType, HttpError } from "@gnu-taler/web-util/lib/index.browser"; import { h, VNode } from "preact"; import { Loading } from "../../../../components/exception/loading.js"; import { MerchantBackend } from "../../../../declaration.js"; import { useInstanceKYCDetails } from "../../../../hooks/instance.js"; import { ListPage } from "./ListPage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; interface Props { onUnauthorized: () => VNode; @@ -38,10 +39,20 @@ export default function ListKYC({ onNotFound, }: Props): VNode { const result = useInstanceKYCDetails(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } const status = result.data.type === "ok" ? undefined : result.data.status; diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx index 3b06b387d..82556d25a 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/create/index.tsx @@ -19,7 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpError } from "@gnu-taler/web-util/lib/index.browser"; +import { ErrorType, HttpError } from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; @@ -30,6 +30,7 @@ import { useOrderAPI } from "../../../../hooks/order.js"; import { useInstanceProducts } from "../../../../hooks/product.js"; import { Notification } from "../../../../utils/types.js"; import { CreatePage } from "./CreatePage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export type Entity = { request: MerchantBackend.Orders.PostOrderRequest; @@ -55,19 +56,36 @@ export default function OrderCreate({ const detailsResult = useInstanceDetails(); const inventoryResult = useInstanceProducts(); - if (detailsResult.clientError && detailsResult.isUnauthorized) - return onUnauthorized(); - if (detailsResult.clientError && detailsResult.isNotfound) - return onNotFound(); if (detailsResult.loading) return ; - if (!detailsResult.ok) return onLoadError(detailsResult); - - if (inventoryResult.clientError && inventoryResult.isUnauthorized) - return onUnauthorized(); - if (inventoryResult.clientError && inventoryResult.isNotfound) - return onNotFound(); if (inventoryResult.loading) return ; - if (!inventoryResult.ok) return onLoadError(inventoryResult); + + if (!detailsResult.ok) { + if ( + detailsResult.type === ErrorType.CLIENT && + detailsResult.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + detailsResult.type === ErrorType.CLIENT && + detailsResult.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(detailsResult); + } + + if (!inventoryResult.ok) { + if ( + inventoryResult.type === ErrorType.CLIENT && + inventoryResult.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + inventoryResult.type === ErrorType.CLIENT && + inventoryResult.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(inventoryResult); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx index 986c46b95..4d0d48e47 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/details/index.tsx @@ -16,6 +16,7 @@ import { useTranslationContext, HttpError, + ErrorType, } from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; @@ -25,6 +26,7 @@ import { MerchantBackend } from "../../../../declaration.js"; import { useOrderAPI, useOrderDetails } from "../../../../hooks/order.js"; import { Notification } from "../../../../utils/types.js"; import { DetailPage } from "./DetailPage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export interface Props { oid: string; @@ -48,10 +50,20 @@ export default function Update({ const { i18n } = useTranslationContext(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx index bd0924808..9a367291f 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -37,6 +38,7 @@ import { import { Notification } from "../../../../utils/types.js"; import { ListPage } from "./ListPage.js"; import { RefundModal } from "./Table.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; interface Props { onUnauthorized: () => VNode; @@ -71,10 +73,20 @@ export default function OrderList({ undefined, ); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } const isPaidActive = filter.paid === "yes" ? "is-active" : ""; const isRefundedActive = filter.refunded === "yes" ? "is-active" : ""; @@ -195,10 +207,20 @@ function RefundModalForTable({ }: RefundProps): VNode { const result = useOrderDetails(id); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( VNode; @@ -55,10 +57,20 @@ export default function ProductList({ const { i18n } = useTranslationContext(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return (
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx index b35606f53..86255b0fe 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/products/update/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -31,6 +32,7 @@ import { MerchantBackend } from "../../../../declaration.js"; import { useProductAPI, useProductDetails } from "../../../../hooks/product.js"; import { Notification } from "../../../../utils/types.js"; import { UpdatePage } from "./UpdatePage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export type Entity = MerchantBackend.Products.ProductAddDetail; interface Props { @@ -55,10 +57,20 @@ export default function UpdateProduct({ const { i18n } = useTranslationContext(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx index 4a235bcea..e7919aab1 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/details/index.tsx @@ -19,12 +19,13 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpError } from "@gnu-taler/web-util/lib/index.browser"; +import { ErrorType, HttpError } from "@gnu-taler/web-util/lib/index.browser"; import { Fragment, h, VNode } from "preact"; import { Loading } from "../../../../components/exception/loading.js"; import { MerchantBackend } from "../../../../declaration.js"; import { useReserveDetails } from "../../../../hooks/reserves.js"; import { DetailPage } from "./DetailPage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; interface Props { rid: string; @@ -45,10 +46,20 @@ export default function DetailReserve({ }: Props): VNode { const result = useReserveDetails(rid); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx index e6c6abc23..d2a821136 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/reserves/list/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -35,6 +36,7 @@ import { import { Notification } from "../../../../utils/types.js"; import { AuthorizeTipModal } from "./AutorizeTipModal.js"; import { CardTable } from "./Table.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; interface Props { onUnauthorized: () => VNode; @@ -67,10 +69,20 @@ export default function ListTips({ TipConfirmation | undefined >(undefined); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return (
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx index ea8f4e7e3..ccbead14d 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/list/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -34,6 +35,7 @@ import { } from "../../../../hooks/templates.js"; import { Notification } from "../../../../utils/types.js"; import { ListPage } from "./ListPage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; interface Props { onUnauthorized: () => VNode; @@ -60,10 +62,20 @@ export default function ListTemplates({ const { deleteTemplate } = useTemplateAPI(); const result = useInstanceTemplates({ position }, (id) => setPosition(id)); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/index.tsx index 044cc7d79..70818268e 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/qr/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -34,6 +35,7 @@ import { } from "../../../../hooks/templates.js"; import { Notification } from "../../../../utils/types.js"; import { QrPage } from "./QrPage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export type Entity = MerchantBackend.Transfers.TransferInformation; interface Props { @@ -54,10 +56,20 @@ export default function TemplateQrPage({ const result = useTemplateDetails(tid); const [notif, setNotif] = useState(undefined); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( <> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx index 73489869b..88790a13a 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -34,6 +35,7 @@ import { } from "../../../../hooks/templates.js"; import { Notification } from "../../../../utils/types.js"; import { UpdatePage } from "./UpdatePage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export type Entity = MerchantBackend.Template.TemplatePatchDetails & WithId; @@ -59,10 +61,20 @@ export default function UpdateTemplate({ const { i18n } = useTranslationContext(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx index b6175bcfb..3c9f82ece 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -34,6 +35,7 @@ import { } from "../../../../hooks/templates.js"; import { Notification } from "../../../../utils/types.js"; import { UsePage } from "./UsePage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export type Entity = MerchantBackend.Transfers.TransferInformation; interface Props { @@ -58,10 +60,20 @@ export default function TemplateUsePage({ const [notif, setNotif] = useState(undefined); const { i18n } = useTranslationContext(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( <> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx index 8ca469c61..8e8d7f2ed 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/transfers/list/index.tsx @@ -19,7 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { HttpError } from "@gnu-taler/web-util/lib/index.browser"; +import { ErrorType, HttpError } from "@gnu-taler/web-util/lib/index.browser"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../../../../components/exception/loading.js"; @@ -27,6 +27,7 @@ import { MerchantBackend } from "../../../../declaration.js"; import { useInstanceDetails } from "../../../../hooks/instance.js"; import { useInstanceTransfers } from "../../../../hooks/transfer.js"; import { ListPage } from "./ListPage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; interface Props { onUnauthorized: () => VNode; @@ -68,10 +69,20 @@ export default function ListTransfer({ (id) => setPosition(id), ); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( */ import { + ErrorType, HttpError, HttpResponse, useTranslationContext, @@ -32,6 +33,7 @@ import { } from "../../../hooks/instance.js"; import { Notification } from "../../../utils/types.js"; import { UpdatePage } from "./UpdatePage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export interface Props { onBack: () => void; @@ -78,10 +80,20 @@ function CommonUpdate( const [notif, setNotif] = useState(undefined); const { i18n } = useTranslationContext(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx index 670fc7218..2a9a7f1b6 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/list/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -34,6 +35,7 @@ import { } from "../../../../hooks/webhooks.js"; import { Notification } from "../../../../utils/types.js"; import { ListPage } from "./ListPage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; interface Props { onUnauthorized: () => VNode; @@ -56,10 +58,20 @@ export default function ListWebhooks({ const { deleteWebhook } = useWebhookAPI(); const result = useInstanceWebhooks({ position }, (id) => setPosition(id)); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx index b9a8674b3..39f3d24cb 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/webhooks/update/index.tsx @@ -20,6 +20,7 @@ */ import { + ErrorType, HttpError, useTranslationContext, } from "@gnu-taler/web-util/lib/index.browser"; @@ -34,6 +35,7 @@ import { } from "../../../../hooks/webhooks.js"; import { Notification } from "../../../../utils/types.js"; import { UpdatePage } from "./UpdatePage.js"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; export type Entity = MerchantBackend.Webhooks.WebhookPatchDetails & WithId; @@ -59,10 +61,20 @@ export default function UpdateWebhook({ const { i18n } = useTranslationContext(); - if (result.clientError && result.isUnauthorized) return onUnauthorized(); - if (result.clientError && result.isNotfound) return onNotFound(); if (result.loading) return ; - if (!result.ok) return onLoadError(result); + if (!result.ok) { + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) + return onUnauthorized(); + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) + return onNotFound(); + return onLoadError(result); + } return ( diff --git a/packages/web-util/src/utils/request.ts b/packages/web-util/src/utils/request.ts index d05a4ec84..8c77814f7 100644 --- a/packages/web-util/src/utils/request.ts +++ b/packages/web-util/src/utils/request.ts @@ -20,6 +20,7 @@ import { base64encode } from "./base64.js"; export enum ErrorType { CLIENT, SERVER, + UNREADABLE, TIMEOUT, UNEXPECTED, } @@ -97,12 +98,9 @@ export async function defaultRequestHandler( url: _url.href, hasToken: !!options.token, status: 0, + options, }; const error: HttpRequestTimeoutError = { - clientError: true, - isNotfound: false, - isUnauthorized: false, - error: undefined, info, type: ErrorType.TIMEOUT, message: "Request timeout", @@ -124,6 +122,7 @@ export async function defaultRequestHandler( _url.href, payload, !!options.token, + options, ); return result; } else { @@ -132,6 +131,7 @@ export async function defaultRequestHandler( _url.href, payload, !!options.token, + options, ); throw new RequestError(error); } @@ -152,6 +152,7 @@ export interface RequestInfo { hasToken: boolean; payload: any; status: number; + options: RequestOptions; } interface HttpResponseLoading { @@ -185,103 +186,60 @@ export type HttpError = | HttpRequestTimeoutError | HttpResponseClientError | HttpResponseServerError + | HttpResponseUnreadableError | HttpResponseUnexpectedError; export interface HttpResponseServerError { ok?: false; loading?: false; - /** - * @deprecated use status - */ - clientError?: false; - /** - * @deprecated use status - */ - serverError: true; type: ErrorType.SERVER; - /** - * @deprecated use payload - */ - error: ErrorDetail; payload: ErrorDetail; status: HttpStatusCode; message: string; - info?: RequestInfo; + info: RequestInfo; } interface HttpRequestTimeoutError { ok?: false; loading?: false; - /** - * @deprecated use type - */ - clientError: true; - /** - * @deprecated use type - */ - serverError?: false; type: ErrorType.TIMEOUT; - info?: RequestInfo; - error: undefined; + info: RequestInfo; - isUnauthorized: false; - isNotfound: false; message: string; } interface HttpResponseClientError { ok?: false; loading?: false; - /** - * @deprecated use type - */ - clientError: true; - /** - * @deprecated use type - */ - serverError?: false; type: ErrorType.CLIENT; - info?: RequestInfo; - /** - * @deprecated use status - */ - isUnauthorized: boolean; - /** - * @deprecated use status - */ - isNotfound: boolean; + info: RequestInfo; status: HttpStatusCode; - /** - * @deprecated use payload - */ - error: ErrorDetail; payload: ErrorDetail; message: string; } interface HttpResponseUnexpectedError { ok?: false; - loading?: false; - /** - * @deprecated use type - */ - clientError?: false; - /** - * @deprecated use type - */ - serverError?: false; + loading: false; type: ErrorType.UNEXPECTED; - info?: RequestInfo; + info: RequestInfo; status?: HttpStatusCode; - /** - * @deprecated use exception - */ - error: unknown; exception: unknown; message: string; } +interface HttpResponseUnreadableError { + ok?: false; + loading: false; + type: ErrorType.UNREADABLE; + + info: RequestInfo; + status: HttpStatusCode; + exception: unknown; + body: string; + message: string; +} export class RequestError extends Error { /** * @deprecated use cause @@ -317,6 +275,7 @@ async function buildRequestOk( url: string, payload: any, hasToken: boolean, + options: RequestOptions, ): Promise> { const dataTxt = await response.text(); const data = dataTxt ? JSON.parse(dataTxt) : undefined; @@ -327,6 +286,7 @@ async function buildRequestOk( payload, url, hasToken, + options, status: response.status, }, }; @@ -337,9 +297,11 @@ async function buildRequestFailed( url: string, payload: any, hasToken: boolean, + options: RequestOptions, ): Promise< | HttpResponseClientError | HttpResponseServerError + | HttpResponseUnreadableError | HttpResponseUnexpectedError > { const status = response?.status; @@ -348,62 +310,52 @@ async function buildRequestFailed( payload, url, hasToken, + options, status: status || 0, }; + const dataTxt = await response.text(); try { - const dataTxt = await response.text(); const data = dataTxt ? JSON.parse(dataTxt) : undefined; if (status && status >= 400 && status < 500) { const error: HttpResponseClientError = { - clientError: true, - isNotfound: status === 404, - isUnauthorized: status === 401, type: ErrorType.CLIENT, status, info, message: data?.hint, - error: data, // remove this payload: data, }; return error; } if (status && status >= 500 && status < 600) { const error: HttpResponseServerError = { - serverError: true, type: ErrorType.SERVER, status, info, message: `${data?.hint} (code ${data?.code})`, - error: data, //remove this payload: data, }; return error; } return { info, + loading: false, type: ErrorType.UNEXPECTED, status, - error: {}, // remove this exception: undefined, - message: "NOT DEFINED", + message: `http status code not handled: ${status}`, }; } catch (ex) { - const error: HttpResponseUnexpectedError = { + const error: HttpResponseUnreadableError = { info, + loading: false, status, - type: ErrorType.UNEXPECTED, - error: ex, + type: ErrorType.UNREADABLE, exception: ex, - message: "NOT DEFINED", + body: dataTxt, + message: "Could not parse body as json", }; return error; } } - -// export function isAxiosError( -// error: AxiosError | any, -// ): error is AxiosError { -// return error && error.isAxiosError; -// }