class
FetchError
export class FetchError extends Error { ... }
A request that failed, carrying why.
One error class with a typed failure, rather than a class per case: a caller that wants to branch reads failure.kind, and one that does not gets a message that already says what happened.
type
Parse
export type Parse<T> = (value: mixed) =>
| {| readonly ok: true, readonly value: T |}
| {| readonly ok: false, readonly issues: $ReadOnlyArray<mixed> |};
A function that checks what arrived and narrows it.
A function rather than a schema object, so this module depends on no validator: @uniflowed/validator's parser(User) is exactly this shape, and so is a hand-written check.
type
FetchConfig
export type FetchConfig = {|
readonly baseURL?: string,
readonly headers?: { readonly [string]: string },
/** Abort a request that has not answered. Defaults to 30 seconds. */
readonly timeout?: number,
/** How many further attempts a retriable failure gets. Defaults to none. */
readonly retries?: number,
/** Milliseconds before the first retry; doubles each time. Defaults to 200. */
readonly retryDelay?: number,
/** Swap in a different `fetch`, which is how a test avoids the network. */
readonly fetch?: typeof fetch,
|};
How a client behaves for every request it makes.
type
RequestOptions
export type RequestOptions<T> = {|
/**
* The verb.
*
* `QUERY` is a `GET` with a body — safe, idempotent, and what a search too
* large for a URL has been faking with a `POST` for twenty years. It is
* retried like the other safe methods below, and a `405` or `501` in answer
* to one is reported as what it usually is; see [`describe`].
*/
readonly method?: "GET" | "HEAD" | "QUERY" | "POST" | "PUT" | "PATCH" | "DELETE",
/** Sent as JSON unless it is already a `BodyInit`. */
readonly body?: mixed,
readonly headers?: { readonly [string]: string },
readonly searchParams?: { readonly [string]: string | number | boolean },
readonly signal?: AbortSignal,
readonly timeout?: number,
readonly retries?: number,
/** Checked against the parsed body; its failure is the request's failure. */
readonly parse?: Parse<T>,
|};
One request.
type
FetchClient
export type FetchClient = {|
readonly request: <T>(path: string, options?: RequestOptions<T>) => Promise<T>,
readonly raw: (path: string, options?: RequestOptions<mixed>) => Promise<Response>,
/** A client with more defaults applied on top of this one's. */
readonly extend: (config: FetchConfig) => FetchClient,
|};
A configured client.
function
createFetch
export function createFetch(config?: FetchConfig): FetchClient { ... }
A client with these defaults.
Creating a client rather than exporting a function per verb, because the base URL, the headers and the retry policy belong to a *service* — and an application talks to more than one.