Skip to Content
ExecutorscreateFetchExecutor

createFetchExecutor(baseURL, options?)@routar/core

Uses the native fetch API. Ideal for SSR where per-request dynamic headers are needed. Built into @routar/core — no additional package required.

import { createFetchExecutor } from '@routar/core' const executor = createFetchExecutor('https://api.example.com')

Options

createFetchExecutor(baseURL, { defaultHeaders: async () => { const token = await getServerToken() return token ? { Authorization: `Bearer ${token}` } : {} }, plugins: [logger()], retry: 2, timeout: 5_000, })
OptionTypeDescription
defaultHeaders() => Promise<Record<string, string>> | Record<string, string>Applied to every request. Evaluated per-request, so safe for SSR token injection.
pluginsExecutorPlugin[]Plugins applied before the fetch call
retrynumber | { count, shouldRetry? }Number of retries on failure
timeoutnumberPer-attempt timeout in milliseconds — throws TimeoutError on expiry

Dynamic base URL

baseURL accepts a static string or a sync/async factory called on every request. This is useful when the origin depends on the runtime environment — e.g. an absolute URL on the server (SSR) but a relative path on the client (CSR) — without maintaining two separate executors:

import { createFetchExecutor } from '@routar/core' const executor = createFetchExecutor( () => (typeof window === 'undefined' ? 'http://localhost:3000/api' : '/api'), )

The factory is evaluated per-request, so it always reflects the current environment. An async factory works too (e.g. resolving the origin from an async config source).

Empty responses

Responses with status 204, 205, or 304 resolve to null. A 200 response with an empty body also resolves to null instead of throwing a SyntaxError.

HttpError

Non-2xx responses throw HttpError. The parsed JSON error payload is available on .body (or null if the body was empty or not JSON):

import { HttpError } from '@routar/core' try { await todoApi.getDetail({ path: { id: 999 } }) } catch (err) { if (err instanceof HttpError) { console.log(err.status) // 404 console.log(err.statusText) // 'Not Found' console.log(err.body) // { message: 'Not found' } | null } }

Query parameter serialization

Arrays are serialized as repeated keys: ids=1&ids=2. This differs from Axios’s default (ids[]=1&ids[]=2). If you switch executors and use array query params, verify your server-side parsing is compatible.

SSR usage (Next.js)

import { createFetchExecutor } from '@routar/core' export const serverExecutor = createFetchExecutor(process.env.API_BASE_URL!, { defaultHeaders: async () => { const { cookies } = await import('next/headers') const token = (await cookies()).get('access_token')?.value return token ? { Authorization: `Bearer ${token}` } : {} }, timeout: 10_000, })

defaultHeaders is called on every request, so it picks up the current request’s cookies in Server Components and Route Handlers.

Last updated on