So you want to show a different error message in React based on the HTTP status code you got? Try this:
import * as React from "react";
class InvalidRequestError extends Error {
readonly type = "InvalidRequestError" as const;
}
class UnexpectedError extends Error {
readonly type = "UnexpectedError" as const;
}
type ResponseError = UnexpectedError | InvalidRequestError;
export default function App() {
const [error, setError] = React.useState<ResponseError>();
React.useEffect(() => {
async function doRequest() {
const response = await fetch("https://httpstat.us/400");
if (response.ok) {
// Store response body normally
return;
}
if (response.status === 400) {
setError(new InvalidRequestError());
} else {
setError(new UnexpectedError());
}
}
doRequest();
}, []);
return (
<div className="App">
<h1>Error</h1>
<h2>Status type was: {error && error.type}</h2>
{error && error.type === "InvalidRequestError"
? "Invalid request"
: "Unexpected error"}
</div>
);
}
Why not just store the status code in the component's state?
You totally can. This is just an abstraction one level higher from that. The goal later on for me is to move these fetch-calls to a new module – a module that would only talk in terms of domain language, so:
export async function getUser(id: number) : Promise<User> {
const response = await fetch("https://api.example.com/user/" + id);
if (response.ok) {
// Return the found user object
return;
}
if (response.status === 404) {
throw new UserNotFound();
} else {
throw new UnexpectedError();
}
}
See what happens here? The caller of this function doesn't (and shouldn't) know anything about HTTP or where the user was gotten from. It could've come through WebSockets for all we know. This means the caller wouldn't have access to the HTTP statuses anymore either, which is a good thing so our HTTP layer doesn't leak to our view layer.
So our first example would turn into something like this
import * as React from "react";
import { getUser, ResponseError } from "./services/users";
export default function App() {
const [error, setError] = React.useState<ResponseError>();
React.useEffect(() => {
async function doRequest() {
try {
const user = await getUser(123);
// Store the user normally
} catch (error) {
setError(error)
}
}
doRequest();
}, []);
return (
<div className="App">
<h1>Error</h1>
<h2>Status type was: {error && error.type}</h2>
{error && error.type === "InvalidRequestError"
? "Invalid request"
: "Unexpected error"}
</div>
);
}
Top comments (0)