Built on Fetch. API-compatible with Fetch.
2 kB, with built-in non-throw mode, types, Standard Schema, throw on non-2xx, timeouts, and retries.
npm install @jynxio/query
const handle = await query.safe(url);
handle.ok && handle.data; // Response
handle.ok || handle.error; // unknownthen() and catch() infer types.
query(url)
.then((res) => 1 as const) // res: Response
.then((num) => 2 as const) // num: 1
.then((num) => 3 as const); // num: 2
query(url)
.then((res) => 1 as const) // res: Response
.catch((err) => 2 as const) // err: unknown
.then((num) => 3 as const); // num: 1 | 2json() supports Standard Schema.
import * as z from "zod";
const res = await query(url); // res: Response
const raw = await res.json(); // raw: JSONData
const num = await res.json(z.number()); // num: number
type JSONData = null | boolean | number | string | JSONData[] | { [key: string]: JSONData };How to customize?
import { Query } from "@jynxio/query";
const customQuery = new Query({ shouldThrow });
function shouldThrow(res: Response): boolean {
if (res.ok) return false;
if (res.type === "opaque") return false;
return true;
}By default, a non-2xx response (unless opaque) is treated as an error. The error is the original response.
const handle = await query.safe(url);
if (handle.ok) return;
const isRes = handle.error instanceof Response;
if (!isRes) return;
handle.error.text();How to customize?
import { Query } from "@jynxio/query";
const customQuery = new Query({
attemptTimeout: 10_000,
overallTimeout: 100_000,
});By default, each attempt times out after 10s; the overall call has no limit.
How to customize?
import { Query } from "@jynxio/query";
const customQuery = new Query({ shouldRetry });
type ShouldRetryProps = {
/** Attempt number, starting at 1. */
no: number;
/** Input from the previous attempt. */
input: Request;
/** Output from the previous attempt. */
output: { ok: true; data: Response } | { ok: false; error: unknown };
};
function shouldRetry(prevAttempt: ShouldRetryProps): number | false {
/** Retry after 3 seconds. */
if (prevAttempt.no <= 5) return 3_000;
/**
* Stop retrying and exit the query.
*
* Resolve with prevAttempt.output.data if successful;
* otherwise, throw prevAttempt.output.error.
*/
return false;
}By default, retries happen when all of the following apply:
- The request was not manually aborted.
- The overall call did not time out.
- The retry count is at most 2.
- The Request method is GET, PUT, HEAD, DELETE, OPTIONS, or TRACE.
- The underlying FetchLike rejects, or the Response status is 408, 413, 429, 500, 502, 503, or 504.
By default, Retry-After takes precedence; otherwise, exponential backoff is used. Both include jitter.