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

FAQ & Troubleshooting

Common Questions

How do I handle query parameters?

Use a path function:

const search = get<{ query: string; page?: number }, User[]>((input) => { const params = new URLSearchParams({ q: input.query }); if (input.page) params.set('page', input.page.toString()); return `/users/search?${params}`; });

How do I add authentication to all requests?

Use a global beforeRequest hook:

hooks: { beforeRequest: async (url, init) => ({ url, init: { ...init, headers: { ...init.headers, Authorization: `Bearer ${getToken()}` } }, }), }

What’s the difference between hooks and custom handlers?

  • Hooks — Apply to many endpoints (global, group, or endpoint level). Best for cross-cutting concerns: auth, logging, retries, token refresh.
  • Custom handlers — Apply to one endpoint, replacing the default JSON behavior. Best for: file uploads, Blob downloads, non-JSON responses, response transformation.

Can I use endpoint-fetcher in Node.js?

Yes — provide a fetch implementation:

import fetch from 'node-fetch'; const api = createApiClient(endpoints, { baseUrl: process.env.API_URL, fetch: fetch as any, });

Node 18+ has native fetch, so no polyfill is needed.


How do I cancel a request?

Attach an AbortSignal in a beforeRequest hook:

const controller = new AbortController(); hooks: { beforeRequest: async (url, init) => ({ url, init: { ...init, signal: controller.signal }, }), } // Later: controller.abort();

How do I use different base URLs for different groups of endpoints?

Create separate clients, or override the URL in a group hook:

// Option 1: separate clients const v1Api = createApiClient(endpoints, { baseUrl: 'https://api.example.com/v1' }); const v2Api = createApiClient(endpoints, { baseUrl: 'https://api.example.com/v2' }); // Option 2: override in a hook legacy: group({ hooks: { beforeRequest: async (url, init) => ({ url: url.replace('api.example.com', 'legacy.example.com'), init, }), }, endpoints: { /* ... */ }, }),

Troubleshooting

TypeScript error: “Property does not exist on type” — Your type definition is missing a property that the API returns. Add it to the type, or use a custom handler to transform the response.

“Failed to fetch” / network error — Check CORS headers on your API server, verify baseUrl is correct, and ensure there are no firewall or proxy issues.

“Unexpected token < in JSON at position 0” — The server returned HTML instead of JSON (often a 404 page). Use a custom handler to check response.ok before calling response.json().

Infinite loop / maximum call stack exceeded — A hook is triggering itself recursively. Guard against it by checking the URL:

afterResponse: async (response, url, init) => { if (response.status === 401 && !url.includes('/auth/refresh')) { // safe to call refresh here } return response; },

Plugin hooks not firing — Make sure the plugin is in the plugins array: plugins: [myPlugin()]. Defining a plugin without adding it has no effect.

Autocomplete not working — Make sure you’ve provided explicit type parameters: get<{ id: string }, User>(...) rather than get(...).