-
Notifications
You must be signed in to change notification settings - Fork 0
Cookbook: conditional writes
double-meh lowers REST-correctness intents to the right headers. Background:
Requests & options, Response envelope.
Send the ETag you last saw; the server rejects with 412 if it changed underneath you:
const {data, etag} = await io.full.get('/things/7');
await io.put('/things/7', {...data, name: 'new'}, {ifMatch: etag});io.update does the whole loop for you — GET + ETag, apply your function, conditional PUT, and on a
412 re-read and re-apply (up to a few times), then invalidate the cache:
await io.update('/things/7', thing => ({...thing, views: thing.views + 1}));If the GET returns no ETag, io.update throws an IOError — there is nothing to make the PUT
conditional on. Pass {force: true} to update unconditionally anyway:
await io.update('/things/7', fn, {force: true}); // no ETag → plain PUT, last write winsYour function may be async and may return undefined to mean "no change" (a no-op that resolves to
the current data). See helpers.
Fail instead of overwriting if the resource already exists:
await io.put('/things/7', thing, {ifNoneMatch: '*'});A bare POST is not auto-retried (it is not safe to replay). Add an idempotency key and the same key
is reused across retries, so the server can dedupe:
await io.post('/payments', payment, {idempotencyKey: true, retry: true});
// ^ true → a generated UUID, stable across retriesPass a string to supply your own key.
The cache — on by default for GETs — revalidates automatically: a stale entry is
re-requested with If-None-Match: <stored etag>, and a 304 Not Modified refreshes the entry
(merging the fresh headers) and serves the stored body:
await io.get('/things/7'); // stale entry → conditional GET; 304 → the cached body, no re-download- helpers · retry · cache · Response envelope
Guides
Concepts
Services
Modules
- fetch transport
- keys & URLs
- helpers
- records
- sse
- storage backends
- compression encoders
- Service Worker integration
Cookbook