Client and registration
Create a Fetcher for shared URL, headers, timeout, and interceptor policy. Requests use the runtime's global fetch unless the fetch option supplies another; a client does not own a connection pool or require destroy().
Construction and defaults
new Fetcher(options?: FetcherOptions) accepts the following options. Supplying an options object requires baseURL; omitting the object uses DEFAULT_OPTIONS.
| Option | Default | Contract |
|---|---|---|
baseURL: string | '' | Used by the mutable urlBuilder; relative URLs still need a runtime that accepts them. |
headers?: RequestHeaders | {} | No Content-Type by default; the body interceptor sets it from the body. The client keeps its own copy of a supplied object. Each request gets a defensive, case-insensitive merge. |
timeout?: number | undefined | Milliseconds; no timer until configured. Request 0 disables the inherited timeout. |
urlTemplateStyle? | UrlTemplateStyle.UriTemplate | {id} syntax; Express selects :id. |
interceptors? | New InterceptorManager | Supplied manager is used as-is; it can be shared across clients. |
validateStatus? | 200 <= status < 300 | Used only when constructing the default manager. |
fetch?: FetchImplementation (type) | Global fetch, read at call time | The fetch that sends requests, for a runtime or framework that supplies its own (Tauri, instrumentation) or a test. Timeouts and signals still apply. Like validateStatus, used only when constructing the default manager. |
urlBuilder, headers, and timeout can be changed for subsequent requests. interceptors is readonly as a property, while its registries remain mutable. Each client owns a copy of its headers, so mutating client.headers affects only that client; mutating exported DEFAULT_OPTIONS.headers still changes every client created afterwards, so use request headers instead.
Choosing an entry point
| Method | Input | Resolved value without an explicit extractor |
|---|---|---|
resolveExchange(request, options?) | FetchRequest, RequestOptions | A synchronous FetchExchange; no HTTP I/O. |
exchange(request, options?) | Same | Promise<FetchExchange> after the interceptor pipeline; does not extract a body. |
request<R = FetchExchange>(request, options?) | Same | Promise<R> through the selected extractor; default exchange. |
fetch<R = Response>(url, request = {}, options?) | FetchRequestInit | Promise<R>; default native Response. |
get, head, options, trace | URL, request without method/body, options | Promise<R = Response>; method fixed by the helper. |
post, put, patch, delete | URL, request without method, options | Same, with optional body. |
DEFAULT_REQUEST_OPTIONS selects ResultExtractors.Exchange; DEFAULT_FETCH_OPTIONS selects ResultExtractors.Response. A generic such as get<User>() alone does not parse JSON: select an extractor or call response.json<User>(). Native Fetch may reject unsupported methods such as TRACE. See results and errors.
Named clients
new NamedFetcher(name, options?) extends Fetcher and immediately registers itself in the singleton fetcherRegistrar, which lives on globalThis so a second copy of the package in the same process (its ESM and CommonJS builds, or two versions) shares it. fetcher is the exported default named instance, with DEFAULT_FETCHER_NAME = 'default'; a second copy reuses the default already registered instead of replacing it. Duplicate registration replaces the prior client.
FetcherRegistrar.register(name, client): void, unregister(name): boolean, and get(name): Fetcher | undefined manage entries. requiredGet(name) and the default getter throw Error when absent. Assigning default registers under 'default'; fetchers returns a new Map whose values are the same clients. Unregistering does not abort in-flight requests.
getFetcher(fetcher?, defaultFetcher?) accepts a direct instance, a registry name, or no value. A string is a name and must exist; any other value is used as the fetcher (no instanceof check, so a fetcher from another copy of the package works); a falsy argument chooses the supplied fallback and then the global default. FetcherCapable exposes that optional field. NamedCapable supplies name, and FetcherConfigurer.applyTo(fetcher): void is the structural contract used by configurable extensions.
Complete example
import {
Fetcher,
NamedFetcher,
fetcherRegistrar,
getFetcher,
} from '@ahoo-wang/fetcher';
const local = new Fetcher({
baseURL: 'https://api.example.com',
timeout: 3000,
});
const named = new NamedFetcher('reports', {
baseURL: 'https://reports.example.com',
});
console.assert(getFetcher('reports') === named);
const exchange = local.resolveExchange({ url: '/users/1' });
console.assert(exchange.request.timeout === 3000);
fetcherRegistrar.unregister('reports');Public symbols and source
| Symbol | Implementation |
|---|---|
FetcherOptions | fetcher.ts:57 |
DEFAULT_OPTIONS | fetcher.ts:105 |
RequestOptions | requestOptions.ts:21 |
DEFAULT_REQUEST_OPTIONS | requestOptions.ts:25 |
DEFAULT_FETCH_OPTIONS | requestOptions.ts:30 |
Fetcher | fetcher.ts:129 |
FetcherCapable | fetcherCapable.ts:22 |
getFetcher | fetcherCapable.ts:37 |
DEFAULT_FETCHER_NAME | fetcherRegistrar.ts:19 |
FetcherRegistrar | fetcherRegistrar.ts:41 |
fetcherRegistrar | fetcherRegistrar.ts:172 |
NamedFetcher | namedFetcher.ts:38 |
fetcher | namedFetcher.ts:94 |
NamedCapable | types.ts:141 |
FetcherConfigurer | fetcherConfigurer.ts:39 |
