Overview
A type-safe fetch wrapper with Standard Schema validation, convenient API methods, and custom error handling.
A type-safe fetch wrapper with Standard Schema validation.
Why fetch?
When fetching data from APIs, TypeScript can't verify that the response matches your expected type. You end up with unsafe type assertions that can cause runtime errors.
Before:
const response = await fetch("/api/users/1");
const data = await response.json();
const user = data as User; // 😱 Unsafe type assertion
// If the API returns { name: "John" } instead of { id: 1, name: "John" },
// your app breaks at runtime with no warningAfter:
import { api } from "@zap-studio/fetch";
const user = await api.get("/api/users/1", UserSchema);
// ✨ Typed, validated, and safe!
// If the API response doesn't match UserSchema, you get a clear errorFeatures
- Type-safe requests with automatic type inference
- Runtime validation using Standard Schema (Zod, Valibot, ArkType, etc.)
- Convenient API methods (GET, POST, PUT, PATCH, DELETE)
- Factory pattern for creating pre-configured instances with base URLs
- Custom error handling with FetchError and ValidationError classes
- Full TypeScript support with zero configuration
Installation
npm install @zap-studio/fetchQuick Start
Let's build a type-safe API client for a user management system.
1. Define Your Schema
First, define the shape of your API responses using any Standard Schema library:
import { z } from "zod";
// Define the user schema
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
role: z.enum(["admin", "user", "guest"]),
createdAt: z.string().transform((s) => new Date(s)),
});
type User = z.infer<typeof UserSchema>;2. Make Type-Safe Requests
import { api } from "@zap-studio/fetch";
// Fetch a single user - fully typed and validated
const user = await api.get("https://api.example.com/users/1", UserSchema);
console.log(user.name); // TypeScript knows this is a string
console.log(user.createdAt); // TypeScript knows this is a Date3. Handle Errors Gracefully
import { FetchError, ValidationError } from "@zap-studio/fetch/errors";
try {
const user = await api.get("https://api.example.com/users/1", UserSchema);
console.log(`Hello, ${user.name}!`);
} catch (error) {
if (error instanceof FetchError) {
// HTTP error (404, 500, etc.)
console.error(`API error: ${error.status}`);
} else if (error instanceof ValidationError) {
// Response didn't match schema
console.error("Invalid API response:", error.issues);
}
}Edit on GitHub
Last updated on