Why Zlient?
You might be wondering: "Why do I need another HTTP client? What's wrong with fetch or axios?"
The Problem
1. fetch is too low-level
fetch is great, but it requires boilerplate for everything:
- Checking
res.ok. - Parsing JSON manually.
- Handling timeouts.
- Constructing query strings.
2. axios is huge and loosely typed
Axios is the industry standard, but:
- It adds significant bundle size.
- Its types are often
anyor require manual generic passing (e.g.,axios.get<User>(...)). - It trusts the server blindly. If the server returns data that doesn't match your TypeScript interface, your app crashes at runtime with cryptic errors.
3. Other clients lock you into one validator
Many typed HTTP clients force you to use a specific validation library (usually Zod). This creates vendor lock-in and prevents you from using your preferred tools.
The Zlient Solution
Zlient takes a different approach: Runtime Validation is not optional, but your validator choice is.
Zlient v3 supports Standard Schema — an industry-standard interface implemented by Zod, Valibot, ArkType, and more. Use whichever validation library you prefer!
Comparison
Traditional (axios)
typescript
interface User {
id: string;
name: string;
}
// ⚠️ Runtime Risk: API might return { id: 123 } (number)
// TypeScript won't catch this. Use defaults to "any" internally.
const { data } = await axios.get<User>('/users/1');
// 💥 Crash: data.id.toLowerCase() is not a function
console.log(data.id.toLowerCase());Zlient Way (with any validator!)
typescript
import { z } from 'zod';
const getUser = client.createEndpoint({
method: 'GET',
path: '/users/1',
response: z.object({ id: z.string(), name: z.string() }),
});typescript
import * as v from 'valibot';
const getUser = client.createEndpoint({
method: 'GET',
path: '/users/1',
response: v.object({ id: v.string(), name: v.string() }),
});typescript
import { type } from 'arktype';
const getUser = client.createEndpoint({
method: 'GET',
path: '/users/1',
response: type({ id: 'string', name: 'string' }),
});typescript
// data is strictly typed as { id: string; name: string }
const data = await getUser({});
// ✅ Safe: We know id is a string
console.log(data.id.toLowerCase());Key Benefits
- Fail Fast: If the API changes, Zlient throws a clear validation error immediately. No more debugging "undefined is not a function" deep in your UI components.
- Zero Boilerplate: No more
if (!res.ok) throw new Error(...). - Standardized: Built-in logic for Retries, Timeouts, and Auth means every network call in your app behaves consistently.
- Small: Built on top of
fetch, so it's lightweight. - No Vendor Lock-in: Use Zod, Valibot, ArkType, or any future Standard Schema library. Switch anytime without changing your endpoint definitions.