stitch()
Declare an endpoint and get back a typed, callable function — the core authoring move.
Reach for stitch() to declare a single HTTP call once and get back a typed,
callable function — it is the core authoring move that every other feature
layers onto.
Example
Pass a string when the URL is all you need; pass a config object when you want a
baseUrl, a parameterized path, or a non-GET method. The generic types the
awaited value.
import { } from 'stitchapi';
// String form — the string becomes the path; a full URL is fine.
const = <{ : number; : string }[]>(
'https://api.example.com/users',
);
// Config form — baseUrl + a {param} slot; method defaults to GET.
const = <{ : number; : string }>({
: 'https://api.example.com',
: '/users/{id}',
: 'POST',
});
const = await ();
const = await ({ : { : 1 } });Options
The handful of fields that shape every stitch:
baseUrl+path— the request target.pathmay contain{param}slots and a?querystring; in string form the whole string becomespath.method— the HTTP verb. Defaults toGET. Any verb your transport accepts, includingQUERY.- The input object —
params,query,headers, andbodyall travel in oneStitchInputyou pass at call time:await createUser({ params: { id: 1 } }). - The generic —
stitch<T>(...)types the awaited valueT.
Auth, retry, and validation are configured on the same config object but documented in their own guides — see below — so there is one source of truth per feature.
The QUERY method
Some reads don't fit in a URL. A faceted search, a big list of ids, a nested
filter — encode it as a query string and you hit length limits, proxies that
truncate, and logs that now hold your filter. The usual workaround is to POST
the filter and give up everything a read gets: no caching, and a client that
can't tell the call apart from a write.
QUERY (draft-ietf-httpbis-safe-method-w-body)
is the method for exactly that — safe, idempotent, and cacheable,
with a request body. Set it like any other verb:
const search = stitch({
method: 'QUERY',
baseUrl: 'https://api.example.com',
path: '/orders',
// Responses are spec-cacheable, but opt in — the key folds in the body, so two
// different filters get two entries and cannot collide.
cache: { ttl: '1m', methods: 'QUERY' },
});
await search({ body: { status: ['open', 'held'], region: 'eu', limit: 200 } });StitchAPI treats it as the read it is:
- The body is sent.
GET/HEADhave theirs dropped — the transport forbids one — butQUERYkeeps it, JSON-encoded like any other body. - No idempotency key. With
idempotencyconfigured, aQUERYis not stamped with anIdempotency-Key; there is no side effect to dedupe. Settingidempotencyon one logs the same construction nudge aGETgets. - A 301/302 stays a
QUERY. The downgrade-to-GETon a permanent or temporary redirect is a historical exception granted toPOST, and the draft says it does not apply here — downgrading would drop the body, turning a filtered read into an unfiltered one. A303still means "GET the result at theLocation", for aQUERYas for anything else. cache.methodsaccepts it. Not in the default['GET','HEAD']: like a GraphQLPOST, caching a body-carrying request is explicit.
QUERY is a young method. Check that your server — and every proxy, CDN,
and WAF between you and it — actually routes it before reaching for it;
intermediaries have been known to reject or mangle an unfamiliar verb.
For every field and its default, see Reference → stitch() and Reference → Config types.