Documentation
API Client
Configure every createMicroApi option, including headers, authHeader, fetcher, and onError.
createMicroApi
API client options
Every API starts with a client created by createMicroApi.
createMicroApi defines settings shared by every resource created from that client.
Use it to configure things like the base URL, global headers, auth headers, a custom fetcher, and global error handling.
If something should be shared by many requests, it usually belongs on the client. If it only applies to one endpoint, it usually belongs on that endpoint.
- name
- query key namespace.
- baseUrl
- root URL for endpoint paths.
- headers
- headers sent with every request.
- tokenProvider
- optional token and refresh manager.
- authHeader
- turns an access token into request headers.
- fetcher
- custom fetch implementation.
- onError
- observes request failures.
- extend
- creates another client from this one.
1import { createMicroApi } from "micro-rq";2 3export const api = createMicroApi({4 name: "main",5 baseUrl: "https://api.example.com",6 headers: () => ({7 "x-client": "web",8 }),9 tokenProvider,10 authHeader: (token) => ({11 Authorization: `Bearer ${token}`,12 }),13 fetcher: fetch,14 onError: (error, context) => {15 console.error(context.method, context.url, error);16 },17});name and baseUrl
name is only used inside generated query keys. It is not sent over the network.
baseUrl is joined with each endpoint path before the request is sent.
Use different name values when your app talks to multiple backends so their query keys stay separate.
- Same-origin API
- use
baseUrl: "/api". - External API
- use
baseUrl: "https://api.example.com". - Multiple APIs
- use different
namevalues. - Generated key
nameis the first item in every query key.
1const mainApi = createMicroApi({2 name: "main",3 baseUrl: "https://api.example.com",4});5 6const billingApi = createMicroApi({7 name: "billing",8 baseUrl: "https://billing.example.com",9});10 11// mainApi users key starts with ["main", ...]12// billingApi invoices key starts with ["billing", ...]headers
headers adds global headers to every request made by this client.
It accepts either a normal HeadersInit value or a function. The function can be async.
Request headers can come from three layers: client headers, endpoint headers, and authHeader.
Use client headers for values shared by many requests. Use endpoint headers when the value depends on endpoint variables.
- Static headers
- good for app version, client name, locale, or tenant.
- Async headers
- good when values must be read at request time.
- Merge order
- client
headers, endpointheaders, thenauthHeader. - Override rule
- later headers replace earlier ones.
1const api = createMicroApi({2 name: "main",3 baseUrl: "/api",4 headers: {5 "x-client": "dashboard",6 "x-app-version": "1.4.0",7 },8});1const api = createMicroApi({2 name: "main",3 baseUrl: "/api",4 headers: async () => {5 const locale = localStorage.getItem("locale") ?? "en";6 7 return {8 "accept-language": locale,9 };10 },11});1const users = api.resource("users", {2 detail: api.get<User, { id: string; traceId: string }>(3 ({ id }) => `/users/${id}`,4 {5 headers: ({ traceId }) => ({6 "x-trace-id": traceId,7 }),8 },9 ),10});authHeader
authHeader receives the current access token and returns the headers added to authenticated requests.
Each endpoint can define authMode, which controls whether auth is used for that endpoint. It also controls whether authHeader can run.
authHeader only runs when a token exists and the endpoint authMode is not none.
Most APIs use a Bearer token, but you can return any auth header shape you need.
Key points
- When
authModeis"none", token lookup andauthHeaderare skipped. - When
authModeis"required", a missing token throwsMicroAuthRequiredErrorbefore fetch runs.
1const api = createMicroApi({2 name: "main",3 baseUrl: "/api",4 tokenProvider,5 authHeader: (token) => ({6 Authorization: `Bearer ${token}`,7 }),8});1const api = createMicroApi({2 name: "main",3 baseUrl: "/api",4 tokenProvider,5 authHeader: (token) => ({6 "x-access-token": token,7 }),8});Info
TokenProvider
We will cover tokenProvider next in the Authentication page.
fetcher
fetcher replaces the fetch implementation used by micro-rq.
By default, the package uses globalThis.fetch.
Provide fetcher when you need a mock fetch in tests, when your environment has no global fetch, or when you want to wrap fetch with custom behavior.
If only some endpoints need a custom fetcher, create another client with api.extend() instead of repeating the whole config.
- Tests
- pass a mock fetcher.
- Node environments
- pass a fetch implementation when
globalThis.fetchis unavailable. - Instrumentation
- wrap fetch to measure request duration.
- Session cookies
- use a custom fetcher with
credentials: "include".
Key points
- Do not use
fetcherfor endpoint-specific headers or bodies.
1const api = createMicroApi({2 name: "main",3 baseUrl: "/api",4 fetcher: async (input, init) => {5 const startedAt = performance.now();6 7 try {8 return await fetch(input, init);9 } finally {10 console.log("request took", performance.now() - startedAt);11 }12 },13});1const mockFetcher: typeof fetch = async () =>2 new Response(JSON.stringify({ id: "user-1", name: "Jane" }), {3 status: 200,4 headers: {5 "content-type": "application/json",6 },7 });8 9const testApi = createMicroApi({10 name: "test",11 baseUrl: "https://example.test",12 fetcher: mockFetcher,13});1const sessionApi = createMicroApi({2 name: "session",3 baseUrl: "/api",4 fetcher: (input, init) =>5 fetch(input, {6 ...init,7 credentials: "include",8 }),9});1const uploadApi = api.extend({2 name: "uploads",3 fetcher: createUploadFetcher("avatar"),4});extend()
extend() creates another API client from the current one.
Use it when most settings stay the same, but a few values need to change.
This is especially useful for upload clients that share the same auth and base URL, but use a different fetcher.
- Inherited
- any config you do not override.
- Overridden
- values passed to
extend()replace the base config. - Recommended
- change
nameif the new client should have a separate query-key namespace. - Common use
api.extend({ name: "uploads", fetcher: uploadFetcher }).
1export const api = createMicroApi({2 name: "main",3 baseUrl: "/api",4 tokenProvider,5 authHeader: (token) => ({6 Authorization: `Bearer ${token}`,7 }),8 onError,9});10 11export const uploadApi = api.extend({12 name: "uploads",13 fetcher: createUploadFetcher("avatar"),14});onError
onError is a global error observer for this API client.
It is called for failed HTTP responses, missing required auth, refresh failures, network failures, and response parsing failures.
It does not replace the original error. The package calls onError and then still throws the original error to TanStack Query or your direct caller.
- Logging
- send
errorandcontextto your logger. - Telemetry
- record
context.method,context.url, andcontext.authMode. - Auth cleanup
- detect auth errors and clear app state if needed.
- UI handling
- keep user-facing messages in TanStack Query
onErroror component state.
1const api = createMicroApi({2 name: "main",3 baseUrl: "/api",4 onError: (error, context) => {5 reportApiError({6 error,7 method: context.method,8 path: context.path,9 url: context.url,10 authMode: context.authMode,11 });12 },13});1const userQuery = useQuery({2 ...users.detail.toQuery(userId),3 onError: (error) => {4 // Component-level UI behavior still belongs here.5 toast.error("Could not load user");6 },7});