-
Notifications
You must be signed in to change notification settings - Fork 0
envelope
Every io.full.* call resolves to an envelope: the parsed body plus the status, headers, and the raw Response. The same shape is mixed into thrown BadStatus errors, so a failed request is inspected exactly like a successful one.
import io from 'double-meh';
const env = await io.full.get('https://api.example.com/users/1');
env.data; // parsed body
env.status; // 200
env.ok; // trueFour fields plus the raw response are set immediately:
-
data— the decoded body (JSON parsed forapplication/jsonand*+jsoncontent types, else text;undefinedfor HEAD/OPTIONS, 204, or empty bodies). Malformed JSON throwsFailedIOwith theSyntaxErroron.cause; thedecodeoption forces another parse mode (see Requests & options). -
status— the numeric HTTP status. -
ok— theResponse.okboolean. -
headers— a plain header dict (lower-cased keys;set-cookiecollected into an array). -
response— the untouchedResponsefor anything not modelled here.
const env = await io.full.get(url);
if (env.ok) console.log(env.status, env.headers['content-type'], env.data);The rest are lazy getters that parse a header on access, so you only pay for what you read:
-
etag— the rawETag, orundefined. -
weak—truewhen the ETag is weak (W/"..."). -
lastModified— aDatefromLast-Modified, orundefined. -
location—Locationresolved to an absolute URL against the response URL. -
links— parsedLinkheader as{rel: url}. -
contentType— the rawContent-Type, orundefined. -
retryAfter—Retry-Afteras a number of seconds, or aDate, orundefined. -
serverTiming—Server-Timingas an array of{name, dur?, desc?}.
const env = await io.full.post('https://api.example.com/things', {name: 'Bob'});
env.status; // 201
env.location; // 'https://api.example.com/things/7' (resolved absolute)
env.etag; // '"v1"' or undefinedFailures throw one of four classes exported as io.IOError, io.FailedIO, io.TimedOut, and io.BadStatus (also importable by name). IOError is the base — it extends Error and carries .options; every wrap preserves the original error on .cause.
-
IOError— the base class; carries.options. -
FailedIO— anIOError; transport/network failure. Adds.response(aResponse, orundefinedwhen none arrived). -
TimedOut— aFailedIOwhose message is'Timed out'; produced by thetimeoutoption (milliseconds, implemented withAbortSignal.timeoutcomposed with yoursignalviaAbortSignal.any). -
BadStatus— anIOError(not aFailedIO) thrown for a non-2xx response (unlessignoreBadStatus). It alone mixes in the full envelope shape —.data,.status,.ok,.headers,.response, and every lazy getter — so guard withinstanceof io.BadStatusbefore reading them;e.datais the parsed body, typicallyproblem+json.e.problemis the parsed error envelope regardless of how the service labels it:dataitself when the body decoded structured, else a JSON sniff of a string body (legacy services mislabel their envelopes),undefinedwhen nothing parseable arrived. No schema is imposed — RFC 9457 is the blessed convention, not a requirement; XML and other legacy types plug in viaio.registerMime, whose decode already runs on error bodies.
User aborts are not errors of the library: they pass through as the platform AbortError — never wrapped, never retried. The named export isAbort(error) recognizes them (both AbortError and the TimeoutError of a raw AbortSignal.timeout).
import {io, isAbort} from 'double-meh';
try {
await io.get('https://api.example.com/missing', null, {timeout: 5000});
} catch (e) {
if (e instanceof io.BadStatus) {
e.status; // 404
e.data; // the decoded body: parsed problem+json, or raw text from a legacy service
e.problem; // the parsed error envelope either way, e.g. {title: 'Nope'} — undefined if unparseable
e.problem?.title; // 'Nope'
} else if (e instanceof io.TimedOut) {
// took longer than 5s
} else if (isAbort(e)) {
// cancelled by your own signal
}
}Pass ignoreBadStatus: true to receive the envelope instead of a throw on non-2xx.
Guides
Concepts
Services
Modules
- fetch transport
- keys & URLs
- helpers
- records
- sse
- storage backends
- compression encoders
- Service Worker integration
Cookbook