Type-safe fetch wrapper with Standard Schema validation and error handling
npm install @shkumbinhsn/fetcherType-safe fetch wrapper with Standard Schema validation and error handling.
- 🔒 Type-safe API calls with full TypeScript support
- ✅ Response validation using any Standard Schema compatible library (Zod, Valibot, etc.)
- 🎯 Structured error handling with typed error responses
- 🚀 Extended RequestInit interface - works exactly like fetch with extra features
- 📦 Tiny bundle size with minimal dependencies
``bash`
npm install @shkumbinhsn/fetcher
`typescript
import { fetcher } from '@shkumbinhsn/fetcher';
import { z } from 'zod';
// Define your schema
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email()
});
// Basic usage (works exactly like fetch)
const data = await fetcher('/api/users');
// With schema validation
const user = await fetcher('/api/users/123', {
schema: UserSchema
});
// user is fully typed as { id: string, name: string, email: string }
console.log(user.name);
`
`typescript
// GET request
const user = await fetcher('/api/users/123', {
schema: UserSchema
});
// POST request
const newUser = await fetcher('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'John', email: 'john@example.com' }),
schema: UserSchema
});
// With authentication
const user = await fetcher('/api/users/123', {
headers: { 'Authorization': 'Bearer your-token' },
schema: UserSchema
});
`
`typescript
import { defineError, fetcher } from '@shkumbinhsn/fetcher';
import { z } from 'zod';
// Define custom errors
const NotFoundError = defineError(
404,
z.object({
message: z.string(),
resource: z.string()
}),
'NotFoundError'
);
const ValidationError = defineError(
400,
z.object({
errors: z.array(z.object({
field: z.string(),
message: z.string()
}))
}),
'ValidationError'
);
// Use in API calls
try {
const user = await fetcher('/api/users/123', {
schema: UserSchema,
errors: [NotFoundError, ValidationError]
});
} catch (error) {
if (error instanceof NotFoundError) {
// error.data is fully typed
console.log(Not found: ${error.data.resource});${err.field}: ${err.message}
} else if (error instanceof ValidationError) {
// error.data.errors is fully typed
error.data.errors.forEach(err =>
console.log()`
);
}
}
`typescript
import { useQuery, useMutation } from '@tanstack/react-query';
import { fetcher } from '@shkumbinhsn/fetcher';
// Query
const { data, error } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetcher(/api/users/${userId}, {
schema: UserSchema,
errors: [NotFoundError]
})
});
// Mutation
const mutation = useMutation({
mutationFn: (userData: CreateUserInput) =>
fetcher('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(userData),
schema: UserSchema,
errors: [ValidationError]
})
});
`
The library exports a FetcherRequestInit type that extends the standard RequestInit:
`typescript
import type { FetcherRequestInit } from '@shkumbinhsn/fetcher';
interface MyRequestInit extends FetcherRequestInit
// Your custom properties
}
function myFetch(url: string, init: MyRequestInit) {
return fetcher(url, init);
}
`
`typescript`
function fetcher
input: RequestInfo | URL,
init?: FetcherRequestInit
): Promise
The main fetch wrapper function that extends the standard fetch API with:schema?: TResponse
- - Optional response validation schemaerrors?: ApiErrorStatic
- - Optional custom error types
`typescript`
function defineError
statusCode: number,
schema: TSchema,
name?: string
): ApiErrorStatic
Create typed error classes for API responses.
Extended RequestInit interface that includes schema and errors` properties.
Any library that implements the Standard Schema specification:
- Zod
- Valibot
- ArkType
- Effect Schema
- And more!
MIT