-
Notifications
You must be signed in to change notification settings - Fork 0
Cookbook: basics
The everyday moves: pick a verb, send some data, read the result. Every verb has the same shape — verb(url, data?, options?) — and returns a promise of the parsed response body.
The default export is the io object; the verbs hang off it. io(...) itself is the low-level callable that every verb is sugar over.
import io from 'double-meh';
const user = await io.get('https://api.example.com/users/1');
// user is the parsed JSON body, ready to useio.get, io.head, io.post, io.put, io.patch, io.delete (aliases io.del / io.remove), and io.options are all available. The second argument is a query for reads (GET / HEAD / OPTIONS / DELETE) and a body for writes (POST / PUT / PATCH).
await io.get('https://api.example.com/users/1'); // read
await io.post('https://api.example.com/users', {name}); // write
await io.delete('https://api.example.com/users/1'); // read-shaped verbio.head and io.options resolve to the full envelope (there is no body to unwrap); the rest resolve to the parsed data.
Pass an object as the second argument and it becomes the query string. Arrays repeat the key; null / undefined values are dropped.
await io.get('https://api.example.com/search', {q: 'kettle', page: 2, tags: ['sale', 'new']});
// -> GET /search?q=kettle&page=2&tags=sale&tags=newThe fields, sort, and expand options are comma-joined into the query for you.
await io.get('https://api.example.com/users/1', null, {fields: ['id', 'name'], expand: ['org']});
// -> ?fields=id,name&expand=orgHand a write verb a plain object and it is JSON.stringify-ed with a Content-Type: application/json header. null is a valid JSON body; undefined sends no body at all.
const created = await io.post('https://api.example.com/things', {name: 'Bob', active: true});Well-known body types — FormData, Blob, URLSearchParams, ArrayBuffer / typed arrays, and ReadableStream — are passed through untouched, so the platform sets the right Content-Type (including the multipart boundary). Do not set Content-Type yourself for FormData.
const form = new FormData();
form.append('title', 'Sunset');
form.append('photo', fileInput.files[0]);
await io.post('https://api.example.com/photos', form);
const blob = new Blob([bytes], {type: 'application/pdf'});
await io.put('https://api.example.com/docs/1', blob);io.full (and io.full.get, io.full.post, ...) resolves to the response envelope instead of just the body — status, headers, and hoisted metadata like etag, location, and links.
const env = await io.full.post('https://api.example.com/things', {name: 'Bob'});
env.status; // 201
env.data; // parsed body
env.location; // absolute URL, resolved from the Location header
env.etag; // '"v1"', if the server sent one
env.headers; // a plain header dictionaryA non-2xx response throws io.BadStatus, which carries the parsed error body on .data and the code on .status. A network-level failure throws io.FailedIO (its subclass io.TimedOut marks a timeout). Both extend the common base io.IOError, but neither extends the other, so the two instanceof branches are independent. A user abort passes through as the platform AbortError — never wrapped.
try {
await io.get('https://api.example.com/missing');
} catch (error) {
if (error instanceof io.BadStatus) {
console.warn(error.status, error.data); // e.g. 404, {title: 'Nope'}
} else if (error instanceof io.FailedIO) {
console.error('network failure', error.message);
}
}To keep a non-2xx as data instead of a throw, pass {ignoreBadStatus: true} and read io.full.
const env = await io.full.get('https://api.example.com/maybe', null, {ignoreBadStatus: true});
if (!env.ok) console.warn('soft failure', env.status);Verbs are just promises — fan them out with Promise.all. Identical concurrent GETs are collapsed into a single network call automatically (see deduping).
const [user, orders, prefs] = await Promise.all([
io.get('https://api.example.com/users/1'),
io.get('https://api.example.com/users/1/orders'),
io.get('https://api.example.com/users/1/prefs')
]);Guides
Concepts
Services
Modules
- fetch transport
- keys & URLs
- helpers
- records
- sse
- storage backends
- compression encoders
- Service Worker integration
Cookbook