Skip to content

Instantly share code, notes, and snippets.

@WomB0ComB0
Created July 10, 2024 19:54
Show Gist options
  • Save WomB0ComB0/3df9cfddea01c9aebc54a890113260bb to your computer and use it in GitHub Desktop.
Save WomB0ComB0/3df9cfddea01c9aebc54a890113260bb to your computer and use it in GitHub Desktop.
TypeSafe http requests with zod validation
import { z } from "zod";
import { PostSchema } from "@/schema/posts";
import { CommentsSchema } from "@/schema/comments";
export function createAPIClient() {
async function _fetch<T extends z.ZodTypeAny>(
input: RequestInfo,
init: RequestInit,
type: T
): Promise<z.infer<T>> {
const headers = new Headers(init?.headers);
const res = await fetch(input, { ...init, headers });
if (!res.ok) {
throw new Error(res.statusText);
}
const data = await res.json();
const result = await type.safeParseAsync(data);
if (!result.success) {
throw new Error(result.error.message);
}
return result.data;
}
return {
posts: {
get: (slug: string) => _fetch(`/api/posts/${slug}`, { method: "GET" }, PostSchema),
getAll: () => _fetch('/api/posts', { method: 'GET' }, z.array(PostSchema)),
post: {
create: (post: z.infer<typeof PostSchema>) => _fetch('/api/v1/posts', { method: 'POST' }, PostSchema),
update: (post: z.infer<typeof PostSchema>) => _fetch(`/api/v1/posts/${post.id}`, { method: 'PUT', body: JSON.stringify(post) }, PostSchema),
delete: (postId: string) => _fetch(`/api/v1/posts/${postId}`, { method: 'DELETE' }, z.object({ success: z.boolean() })),
}
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment