Refactor SWR mutation handling: replace Error with NetworkError for improved error management and add error handling in fetchers
parent
8f9c03f400
commit
82a4750c76
|
@ -14,7 +14,7 @@ import {
|
||||||
RestartMachine,
|
RestartMachine,
|
||||||
ShutdownMachine
|
ShutdownMachine
|
||||||
} from "types";
|
} from "types";
|
||||||
import { Key, mutationFetcher, useSWRMutation } from "units/swr";
|
import { Key, NetworkError, mutationFetcher, useSWRMutation } from "units/swr";
|
||||||
import { usePingTrigger } from "../hooks";
|
import { usePingTrigger } from "../hooks";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -34,6 +34,7 @@ const MachineContainer: React.FC<Props> = ({ machine, viewMode }) => {
|
||||||
|
|
||||||
const manageActionResponse = useCallback(
|
const manageActionResponse = useCallback(
|
||||||
(response: MachineActionResult) => {
|
(response: MachineActionResult) => {
|
||||||
|
debugger;
|
||||||
addLog(`Success: ${response.success}. Status: ${response.status}`);
|
addLog(`Success: ${response.success}. Status: ${response.status}`);
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
blip.success(response.status);
|
blip.success(response.status);
|
||||||
|
@ -48,20 +49,23 @@ const MachineContainer: React.FC<Props> = ({ machine, viewMode }) => {
|
||||||
onSuccess: manageActionResponse
|
onSuccess: manageActionResponse
|
||||||
});
|
});
|
||||||
|
|
||||||
const { trigger: shutdownMachineTrigger } = useSWRMutation<MachineShutdown, Error, Key, ShutdownMachine>(
|
const { trigger: shutdownMachineTrigger } = useSWRMutation<MachineShutdown, NetworkError, Key, ShutdownMachine>(
|
||||||
endpoints.network.machine.shutdown,
|
endpoints.network.machine.shutdown,
|
||||||
mutationFetcher<ShutdownMachine>,
|
mutationFetcher<ShutdownMachine>,
|
||||||
{
|
{
|
||||||
onError: err => blip.error(err.message),
|
onError: err => {
|
||||||
|
debugger;
|
||||||
|
blip.error(err.message);
|
||||||
|
},
|
||||||
onSuccess: manageActionResponse
|
onSuccess: manageActionResponse
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const { trigger: restartMachineTrigger } = useSWRMutation<MachineRestarted, Error, Key, RestartMachine>(
|
const { trigger: restartMachineTrigger } = useSWRMutation<MachineRestarted, NetworkError, Key, RestartMachine>(
|
||||||
endpoints.network.machine.restart,
|
endpoints.network.machine.restart,
|
||||||
mutationFetcher<RestartMachine>,
|
mutationFetcher<RestartMachine>,
|
||||||
{
|
{
|
||||||
onError: err => blip.error(err.message),
|
onError: err => blip.error(err.serverError.message || err.message),
|
||||||
onSuccess: manageActionResponse
|
onSuccess: manageActionResponse
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { msToMinAndSec } from "../../../../utils/time";
|
||||||
import { endpoints } from "../../../../utils/api";
|
import { endpoints } from "../../../../utils/api";
|
||||||
import { Machine, MachineWaked, WakeMachine } from "types";
|
import { Machine, MachineWaked, WakeMachine } from "types";
|
||||||
import { usePingTrigger } from "../../hooks";
|
import { usePingTrigger } from "../../hooks";
|
||||||
import { Key, mutationFetcher, useSWRMutation } from "units/swr";
|
import { Key, mutationFetcher, NetworkError, useSWRMutation } from "units/swr";
|
||||||
|
|
||||||
const initialState = { on: false };
|
const initialState = { on: false };
|
||||||
const defaultPingInterval = 1200000; //20 minutes
|
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,
|
endpoints.network.machine.wake,
|
||||||
mutationFetcher<WakeMachine>,
|
mutationFetcher<WakeMachine>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { MachinePinged, PingMachine } from "types";
|
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 { blip } from "utils";
|
||||||
import { endpoints } from "utils/api";
|
import { endpoints } from "utils/api";
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ const usePingTrigger = (options: PingTriggerOptions) => {
|
||||||
const { onSuccess } = options;
|
const { onSuccess } = options;
|
||||||
const onError = useMemo(() => options.onError || ((error: Error) => blip.error(error.message)), [options.onError]);
|
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,
|
endpoints.network.machine.ping,
|
||||||
mutationFetcher<PingMachine>,
|
mutationFetcher<PingMachine>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,17 +3,21 @@ import CacheSettingsComponent from "./CacheSettingsComponent";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { endpoints } from "utils/api";
|
import { endpoints } from "utils/api";
|
||||||
import { blip } from "utils";
|
import { blip } from "utils";
|
||||||
import { useSWRMutation, mutationFetcher, Key } from "units/swr";
|
import { useSWRMutation, mutationFetcher, Key, NetworkError } from "units/swr";
|
||||||
|
|
||||||
const CacheSettingsContainer: React.FC = () => {
|
const CacheSettingsContainer: React.FC = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { trigger } = useSWRMutation<void, Error, Key, void>(endpoints.system.resetCache, mutationFetcher<void>, {
|
const { trigger } = useSWRMutation<void, NetworkError, Key, void>(
|
||||||
|
endpoints.system.resetCache,
|
||||||
|
mutationFetcher<void>,
|
||||||
|
{
|
||||||
onError: err => {
|
onError: err => {
|
||||||
blip.error(err.message);
|
blip.error(err.message);
|
||||||
},
|
},
|
||||||
onSuccess: () => blip.info(t("Settings.Cache.ResetInfo"))
|
onSuccess: () => blip.info(t("Settings.Cache.ResetInfo"))
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const handleResetCache = useCallback(() => trigger(), [trigger]);
|
const handleResetCache = useCallback(() => trigger(), [trigger]);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import { acquire as fetchTuitioData } from "@flare/tuitio-client";
|
import { acquire as fetchTuitioData } from "@flare/tuitio-client";
|
||||||
|
import { NetworkError, ServerError } from "./errors";
|
||||||
|
|
||||||
const getHeaders = (): HeadersInit => {
|
const getHeaders = (): HeadersInit => {
|
||||||
const { token } = fetchTuitioData();
|
const { token } = fetchTuitioData();
|
||||||
|
@ -20,18 +21,36 @@ const getHeaders = (): HeadersInit => {
|
||||||
return headers;
|
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 }) {
|
async function mutationFetcher<Command>(url: string, { arg }: { arg: Command }) {
|
||||||
const hasBody = arg !== undefined && arg !== null;
|
const hasBody = arg !== undefined && arg !== null;
|
||||||
const headers = getHeaders();
|
const headers = getHeaders();
|
||||||
const body = hasBody ? JSON.stringify(arg) : undefined;
|
const body = hasBody ? JSON.stringify(arg) : undefined;
|
||||||
|
|
||||||
return fetch(url, {
|
const res = await fetch(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers,
|
headers,
|
||||||
body
|
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 };
|
export { fetcher, mutationFetcher };
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { Key } from "swr";
|
||||||
import useSWRMutation from "swr/mutation";
|
import useSWRMutation from "swr/mutation";
|
||||||
|
|
||||||
export * from "./fetchers";
|
export * from "./fetchers";
|
||||||
|
export * from "./errors";
|
||||||
|
|
||||||
export { useSWR, useSWRMutation };
|
export { useSWR, useSWRMutation };
|
||||||
export type { Key };
|
export type { Key };
|
||||||
|
|
Loading…
Reference in New Issue