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,
})| Option | Type | Description |
|---|---|---|
defaultHeaders | () => Promise<Record<string, string>> | Record<string, string> | Applied to every request. Evaluated per-request, so safe for SSR token injection. |
plugins | ExecutorPlugin[] | Plugins applied before the fetch call |
retry | number | { count, shouldRetry? } | Number of retries on failure |
timeout | number | Per-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.