Skip to content

Instantly share code, notes, and snippets.

@gimenete
Last active March 15, 2024 16:05
Show Gist options
  • Star 38 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save gimenete/dd1886288ee3d3baaeae573ca226048f to your computer and use it in GitHub Desktop.
Save gimenete/dd1886288ee3d3baaeae573ca226048f to your computer and use it in GitHub Desktop.
A wrapper around the fetch function that validates the response body against a Zod schema
import z from "zod";
export async function safeFetch<T>(
schema: z.Schema<T>,
input: RequestInfo,
init?: RequestInit
): Promise<T> {
const response = await fetch(input, init);
if (!response.ok) {
throw newHTTPError("Unsuccessful response", response, init?.method);
}
const json = await response.json().catch(() => {
throw newHTTPError("Not a JSON body", response, init?.method);
});
const result = schema.safeParse(json);
if (!result.success) {
throw newHTTPError("Unexpected response schema", response, init?.method);
}
return result.data;
}
async function newHTTPError(reason: string, response: Response, method?: string) {
const text = await response.text().catch(() => null);
const message = `Error fetching ${method} ${response.url} ${response.status}. ${reason}`;
console.error(`${message}. Response body: ${text}`);
return new HTTPError(response.status, message);
}
export class HTTPError extends Error {
constructor(public status: number, message: string) {
super(message);
this.status = status;
}
}
@jimniels
Copy link

Shouldn't function newHTTPError(...) be async function newHTTPError(...) because it's using await inside?

@gimenete
Copy link
Author

@jimniels right, updated! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment