Refactor SWR mutation handling: replace Error with NetworkError for improved error management and add error handling in fetchers

master^2
Tudor Stanciu 2024-11-16 04:05:16 +02:00
parent 8f9c03f400
commit 82a4750c76
7 changed files with 63 additions and 19 deletions

View File

@ -14,7 +14,7 @@ import {
RestartMachine,
ShutdownMachine
} from "types";
import { Key, mutationFetcher, useSWRMutation } from "units/swr";
import { Key, NetworkError, mutationFetcher, useSWRMutation } from "units/swr";
import { usePingTrigger } from "../hooks";
type Props = {
@ -34,6 +34,7 @@ const MachineContainer: React.FC<Props> = ({ machine, viewMode }) => {
const manageActionResponse = useCallback(
(response: MachineActionResult) => {
debugger;
addLog(`Success: ${response.success}. Status: ${response.status}`);
if (response.success) {
blip.success(response.status);
@ -48,20 +49,23 @@ const MachineContainer: React.FC<Props> = ({ machine, viewMode }) => {
onSuccess: manageActionResponse
});
const { trigger: shutdownMachineTrigger } = useSWRMutation<MachineShutdown, Error, Key, ShutdownMachine>(
const { trigger: shutdownMachineTrigger } = useSWRMutation<MachineShutdown, NetworkError, Key, ShutdownMachine>(
endpoints.network.machine.shutdown,
mutationFetcher<ShutdownMachine>,
{
onError: err => blip.error(err.message),
onError: err => {
debugger;
blip.error(err.message);
},
onSuccess: manageActionResponse
}
);
const { trigger: restartMachineTrigger } = useSWRMutation<MachineRestarted, Error, Key, RestartMachine>(
const { trigger: restartMachineTrigger } = useSWRMutation<MachineRestarted, NetworkError, Key, RestartMachine>(
endpoints.network.machine.restart,
mutationFetcher<RestartMachine>,
{
onError: err => blip.error(err.message),
onError: err => blip.error(err.serverError.message || err.message),
onSuccess: manageActionResponse
}
);

View File

@ -7,7 +7,7 @@ import { msToMinAndSec } from "../../../../utils/time";
import { endpoints } from "../../../../utils/api";
import { Machine, MachineWaked, WakeMachine } from "types";
import { usePingTrigger } from "../../hooks";
import { Key, mutationFetcher, useSWRMutation } from "units/swr";
import { Key, mutationFetcher, NetworkError, useSWRMutation } from "units/swr";
const initialState = { on: false };
const defaultPingInterval = 1200000; //20 minutes
@ -58,7 +58,7 @@ const WakeComponent: React.FC<Props> = ({ machine, addLog, disabled }) => {
}
});
const { trigger: wakeMachineTrigger } = useSWRMutation<MachineWaked, Error, Key, WakeMachine>(
const { trigger: wakeMachineTrigger } = useSWRMutation<MachineWaked, NetworkError, Key, WakeMachine>(
endpoints.network.machine.wake,
mutationFetcher<WakeMachine>,
{

View File

@ -1,6 +1,6 @@
import { useMemo } from "react";
import { MachinePinged, PingMachine } from "types";
import { Key, mutationFetcher, useSWRMutation } from "units/swr";
import { Key, mutationFetcher, NetworkError, useSWRMutation } from "units/swr";
import { blip } from "utils";
import { endpoints } from "utils/api";
@ -12,7 +12,7 @@ const usePingTrigger = (options: PingTriggerOptions) => {
const { onSuccess } = options;
const onError = useMemo(() => options.onError || ((error: Error) => blip.error(error.message)), [options.onError]);
const { trigger: pingMachineTrigger } = useSWRMutation<MachinePinged, Error, Key, PingMachine>(
const { trigger: pingMachineTrigger } = useSWRMutation<MachinePinged, NetworkError, Key, PingMachine>(
endpoints.network.machine.ping,
mutationFetcher<PingMachine>,
{

View File

@ -3,17 +3,21 @@ import CacheSettingsComponent from "./CacheSettingsComponent";
import { useTranslation } from "react-i18next";
import { endpoints } from "utils/api";
import { blip } from "utils";
import { useSWRMutation, mutationFetcher, Key } from "units/swr";
import { useSWRMutation, mutationFetcher, Key, NetworkError } from "units/swr";
const CacheSettingsContainer: React.FC = () => {
const { t } = useTranslation();
const { trigger } = useSWRMutation<void, Error, Key, void>(endpoints.system.resetCache, mutationFetcher<void>, {
onError: err => {
blip.error(err.message);
},
onSuccess: () => blip.info(t("Settings.Cache.ResetInfo"))
});
const { trigger } = useSWRMutation<void, NetworkError, Key, void>(
endpoints.system.resetCache,
mutationFetcher<void>,
{
onError: err => {
blip.error(err.message);
},
onSuccess: () => blip.info(t("Settings.Cache.ResetInfo"))
}
);
const handleResetCache = useCallback(() => trigger(), [trigger]);

View File

@ -0,0 +1,16 @@
export type ServerError = {
title: string;
status: number;
message: string | null;
};
export class NetworkError extends Error {
status: number;
serverError: ServerError;
constructor(message: string, status: number, serverError: ServerError) {
super(message);
this.status = status;
this.serverError = serverError;
}
}

View File

@ -1,5 +1,6 @@
import i18next from "i18next";
import { acquire as fetchTuitioData } from "@flare/tuitio-client";
import { NetworkError, ServerError } from "./errors";
const getHeaders = (): HeadersInit => {
const { token } = fetchTuitioData();
@ -20,18 +21,36 @@ const getHeaders = (): HeadersInit => {
return headers;
};
const fetcher = (url: string) => fetch(url, { method: "GET", headers: getHeaders() }).then(res => res.json());
const fetcher = async (url: string) => {
const res = await fetch(url, { method: "GET", headers: getHeaders() });
if (!res.ok) {
const serverError = (await res.json()) as ServerError;
const error = new NetworkError("An error occurred while fetching the data.", res.status, serverError);
throw error;
}
return res.json();
};
async function mutationFetcher<Command>(url: string, { arg }: { arg: Command }) {
const hasBody = arg !== undefined && arg !== null;
const headers = getHeaders();
const body = hasBody ? JSON.stringify(arg) : undefined;
return fetch(url, {
const res = await fetch(url, {
method: "POST",
headers,
body
}).then(res => res.json());
});
if (!res.ok) {
const serverError = (await res.json()) as ServerError;
const error = new NetworkError("An error occurred while mutating the data.", res.status, serverError);
throw error;
}
return res.json();
}
export { fetcher, mutationFetcher };

View File

@ -3,6 +3,7 @@ import type { Key } from "swr";
import useSWRMutation from "swr/mutation";
export * from "./fetchers";
export * from "./errors";
export { useSWR, useSWRMutation };
export type { Key };