const CACHE_NAME = 'swr-api-v1';
const STAMP_HEADER = 'x-cached-at';
async function open() {
return caches.open(CACHE_NAME);
}
export async function read(request) {
const cache = await open();
const cached = await cache.match(request);
if (!cached) return null;
const stampedAt = Number(cached.headers.get(STAMP_HEADER)) || 0;
const age = Date.now() - stampedAt;
return { response: cached, age };
}
export async function write(request, response) {
const cache = await open();
const body = await response.clone().blob();
const headers = new Headers(response.headers);
headers.set(STAMP_HEADER, String(Date.now()));
const stamped = new Response(body, {
status: response.status,
statusText: response.statusText,
headers,
});
await cache.put(request, stamped);
}
// Evict entries older than maxAge * factor to bound cache size.
export async function staleFactor(maxAge, factor = 10) {
const cache = await open();
const keys = await cache.keys();
const ceiling = maxAge * factor;
await Promise.all(
keys.map(async (request) => {
const hit = await read(request);
if (hit && hit.age > ceiling) await cache.delete(request);
})
);
}
import { read, write } from './swrCache.js';
const inFlight = new Map();
async function revalidate(request, key) {
if (inFlight.has(key)) return inFlight.get(key);
const task = fetch(request)
.then(async (response) => {
if (response.ok) await write(request, response.clone());
return response;
})
.finally(() => inFlight.delete(key));
inFlight.set(key, task);
return task;
}
export async function swrFetch(input, { maxAge = 30_000, init } = {}) {
const request = new Request(input, init);
const key = request.url;
const hit = await read(request);
if (hit && hit.age <= maxAge) {
return { response: hit.response.clone(), isStale: false };
}
if (hit) {
revalidate(request, key); // fire-and-forget refresh
return { response: hit.response.clone(), isStale: true };
}
const fresh = await revalidate(request, key);
return { response: fresh.clone(), isStale: false };
}
import { useEffect, useRef, useState } from 'react';
import { swrFetch } from './swrFetch.js';
export function useSwrResource(url, { maxAge = 30_000 } = {}) {
const [state, setState] = useState({ data: null, error: null, isStale: false });
const cancelled = useRef(false);
useEffect(() => {
cancelled.current = false;
async function load() {
try {
const { response, isStale } = await swrFetch(url, { maxAge });
const data = await response.json();
if (!cancelled.current) setState({ data, error: null, isStale });
} catch (error) {
if (!cancelled.current) setState((s) => ({ ...s, error }));
}
}
load();
return () => {
cancelled.current = true;
};
}, [url, maxAge]);
return state;
}
This snippet implements a stale-while-revalidate (SWR) fetch layer built directly on the browser's native Cache API rather than an in-memory Map, so cached responses survive page reloads and can be shared with a service worker. The SWR pattern serves a cached response immediately when one exists, then kicks off a background network request to refresh the entry, trading absolute freshness for near-instant reads. It is the right choice for data that changes occasionally and tolerates being a few seconds stale — dashboards, config, catalog listings — but the wrong choice for strongly consistent reads like account balances.
In swrCache.js, the module opens a named cache with caches.open and exposes read, write, and staleFactor helpers. Because the Cache API only stores Response objects, freshness metadata is smuggled through a custom x-cached-at header: write clones the response, injects the timestamp, and stores the rewritten Response. read reconstructs the age from that header so callers can decide whether an entry is fresh, stale-but-usable, or fully expired. Cloning matters because a Response body is a one-shot stream — reading it consumes it — so the code always clone()s before storing or returning.
In swrFetch.js, swrFetch ties the policy together. On a hit within maxAge it returns the cached Response and does nothing else. On a stale hit it returns the cached copy immediately and calls revalidate in the background without awaiting it, which is what makes reads feel instant. On a miss it awaits the network. An in-flight Map keyed by URL deduplicates concurrent revalidations so a burst of callers triggers only one network request. Only successful (response.ok) responses are written back, preventing error pages from poisoning the cache.
In useSwrResource.js, a small React hook consumes the wrapper, tracking data, error, and an isStale flag, and guards against setting state after unmount via a cancelled ref. The main trade-off across these files is staleness versus latency, plus the need to clone streams and to bound cache growth with a periodic staleFactor sweep in production.
Related snips
export interface RetryOptions {
retries: number;
baseMs: number;
maxMs: number;
signal?: AbortSignal;
onRetry?: (attempt: number, delay: number, err: unknown) => void;
Exponential backoff with jitter for retries
module Api
module V1
class UsersController < BaseController
def show
user = User.includes(:profile).find(params[:id])
ETags for conditional requests and caching
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
Rails.application.configure do
config.after_initialize do
Bullet.enable = true
Bullet.alert = false
Bullet.bullet_logger = true
Bullet.console = true
N+1 query detection with Bullet gem
json.array! @posts do |post|
json.cache! ['v1', post], expires_in: 1.hour do
json.id post.id
json.title post.title
json.excerpt post.excerpt
json.published_at post.published_at
Fragment caching for expensive JSON serialization
package deps
import (
"net"
"net/http"
"time"
HTTP client tuned for production: timeouts, transport, and connection reuse
Share this code
Here's the card — post it anywhere.