Skip to Content
✨ New: Auth Plugin. JWT, OAuth2, API Key, and more authentication strategies out of the box. Read more... 🎉
Hooks

Hooks

Hooks intercept requests and responses at global, group, or endpoint level.

Hook Types

HookSignaturePurpose
beforeRequest(url, init) => Promise<{ url, init }>Modify or inspect the request before it’s sent
afterResponse(response, url, init) => Promise<Response>Inspect or replace the response
onError(error) => Promise<void>Handle or log errors
const api = createApiClient({ /* endpoints */ }, { baseUrl: 'https://api.example.com', hooks: { beforeRequest: async (url, init) => { // Must return { url, init } return { url, init: { ...init, headers: { ...init.headers, 'X-Request-ID': crypto.randomUUID() } } }; }, afterResponse: async (response, url, init) => { // Must return a Response return response; }, onError: async (error) => { // No return value console.error('API error:', error); }, }, });

Hook Levels

Hooks can be defined at three levels — they all stack and run together:

LevelWhereApplies to
PluginPlugin factoryAll endpoints
GlobalClient config hooksAll endpoints
Groupgroup({ hooks: ... })All endpoints in the group and its sub-groups
EndpointThird argument of get(), post(), etc.That endpoint only
const api = createApiClient({ admin: group({ hooks: { // Runs for all endpoints inside 'admin' beforeRequest: async (url, init) => ({ url, init: { ...init, headers: { ...init.headers, 'X-Admin': 'true' } } }), }, endpoints: { createUser: post<Input, Output>( '/admin/users', undefined, { // Runs only for createUser beforeRequest: async (url, init) => { console.log('creating user'); return { url, init }; }, } ), }, }), }, { baseUrl: 'https://api.example.com', hooks: { // Runs for every request beforeRequest: async (url, init) => ({ url, init }), }, });

Execution Order

For beforeRequest: plugin → global → outer group → inner group → endpoint

For afterResponse: endpoint → inner group → outer group → global → plugin (reverse)

onError follows the same order as beforeRequest.

Common Patterns

Authentication

hooks: { beforeRequest: async (url, init) => ({ url, init: { ...init, headers: { ...init.headers, Authorization: `Bearer ${localStorage.getItem('jwt')}` }, }, }), }

Token Refresh on 401

hooks: { afterResponse: async (response, url, init) => { if (response.status === 401 && !url.includes('/auth/')) { const token = await refreshToken(); localStorage.setItem('jwt', token); return fetch(url, { ...init, headers: { ...init.headers, Authorization: `Bearer ${token}` } }); } return response; }, }

Logging

hooks: { beforeRequest: async (url, init) => { console.log(`→ ${init.method} ${url}`); return { url, init }; }, afterResponse: async (response, url, init) => { console.log(`← ${response.status} ${init.method} ${url}`); return response; }, }