Build a fully-working typed client — with auth, caching, retries, timeouts, and dedup active — in five minutes.
pnpm add @developerehsan/api-client
# npm install @developerehsan/api-client
# yarn add @developerehsan/api-clientOptional peer dependencies (install only what you use — nothing is bundled):
pnpm add axios # Axios adapter (default). Skip it to run purely on fetch.
pnpm add zod # optional; the built-in response validator needs no zodRequires TypeScript 5+ and Node 18+ / any modern browser / edge runtime.
Create one file that configures and exports the client. Import it everywhere.
// src/api.ts
import { createClient, defineModule } from '@developerehsan/api-client'
export const api = createClient({
baseURL: 'https://api.example.com',
openapi: { mode: 'runtime' },
auth: { strategy: 'bearer', getToken: () => localStorage.getItem('access_token') },
http: { timeout: 10_000, retry: { attempts: 3 } },
cache: { strategy: 'stale-while-revalidate', ttl: 60_000 },
modules: {
users: defineModule({
methods: {
list: async (ctx, params?: { page?: number }) =>
(await ctx.request({ method: 'GET', path: '/users', query: params })).data,
get: async (ctx, id: string) =>
(await ctx.request({ method: 'GET', path: '/users/{id}', pathParams: { id } })).data,
create: async (ctx, body: { name: string; email: string }) =>
(await ctx.request({ method: 'POST', path: '/users', body })).data,
},
}),
},
})Use it anywhere:
import { api } from './src/api'
const users = await api.users.list({ page: 1 })
const user = await api.users.get('user_42')
const made = await api.users.create({ name: 'Ada', email: 'ada@x.com' })The React + Vite example does exactly this against DummyJSON and shows the results in a UI, with dev logging printing every request/response.
# from the monorepo root
pnpm install
pnpm --filter @developerehsan/api-client build # build the library once
cd examples/react-vite && pnpm dev- Client wiring:
examples/react-vite/src/lib/api/api.config.ts - Direct typed calls in a component:
DirectClientDemo.tsx
| Function | When to use |
|---|---|
createClient(config) |
Quick start, hand-written modules, no OpenAPI spec needed |
createTypedClient<Ops>()(config, descriptors) |
Full end-to-end type-safety — Ops from codegen (codegen) or hand-written (manual types) |
The examples use createTypedClient with codegen because they generate types
from a spec — but codegen isn't required for full type-safety. No OpenAPI
spec yet? See full type-safety without codegen. The
modules & methods page covers both.
- Mental model — understand the pipeline before going deeper
- Modules & methods — how to declare endpoints
- Full type-safety without codegen — hand-write
Ops, same guarantees - Configuration reference — every option