Tag‑aware caching for Axios: stable cache IDs, simple tag invalidation, and a drop‑in Orval mutator on top of axios‑cache‑interceptor.
Tag-aware caching helpers for Axios on top of axios-cache-interceptor.
This library makes it easy to:
npm i @karmaniverous/cached-axios axios axios-cache-interceptor zod
Requires Node 20+.
import {
cachedAxios,
withQuery,
withMutation,
} from '@karmaniverous/cached-axios';
// GET with a stable id; associate id with tags for later invalidation.
await withQuery<User>(
cachedAxios.request,
'user:42', // your stable id
['user:list'], // tags to register
{ url: '/users/42', method: 'get', baseURL: 'https://api.example.com' },
);
// Write and invalidate any ids under these tags.
await withMutation(
cachedAxios.request,
['user:list'], // tags to invalidate
{
url: '/users/42',
method: 'patch',
data: { name: 'Alice' },
baseURL: 'https://api.example.com',
},
);
The helpers forward any object-valued cache options from your base config and
set only what they need (custom id for queries; update map for mutations).
Pass cache: false on a call to disable caching for that request.
buildConfigDeclaratively define your keyspace, then use strongly-typed builders everywhere.
import { buildConfig } from '@karmaniverous/cached-axios';
const cfg = buildConfig({
user: {
byId: undefined,
list: undefined,
},
});
// Generate keys
const id = cfg.user.byId.id(42); // "user:byId:42"
const tag = cfg.user.list.tag(); // "user:list"
Segments can be string | number | (string|number)[] | undefined, and are joined
with : to form keys.
makeCacheHelpersimport { makeCacheHelpers } from '@karmaniverous/cached-axios';
const { query, mutation } = makeCacheHelpers(() => ({
baseURL: 'https://api.example.com',
headers: { Authorization: 'Bearer <token>' },
}));
// Query
await query<User>(
cachedAxios.request,
cfg.user.byId.id(42),
[cfg.user.list.tag()],
{
url: '/users/42',
method: 'get',
},
);
// Mutation + invalidation
await mutation(cachedAxios.request, [cfg.user.list.tag()], {
url: '/users/42',
method: 'patch',
data: { name: 'Bob' },
});
Use the provided mutator to keep generated clients cache-aware.
// orval.config.ts (or .js)
import { orvalMutator } from '@karmaniverous/cached-axios/mutators/orval';
export default {
petstore: {
input: './openapi.yaml',
output: {
target: './src/generated/client.ts',
client: 'axios',
mutator: {
path: '@karmaniverous/cached-axios/mutators/orval',
name: 'orvalMutator',
},
},
},
};
Recommended path: '@karmaniverous/cached-axios/mutators/orval' for generators.
For manual imports, a convenience barrel is available at
'@karmaniverous/cached-axios/mutators'. The root export remains available if
you prefer: import { orvalMutator } from '@karmaniverous/cached-axios'.
The orvalMutator<T, R>(config, options?) shallow-merges options over config
and always resolves to AxiosResponse<T>. It executes via the same shared
cache-aware Axios instance exported as cachedAxios.
cachedAxios)import { cachedAxios } from '@karmaniverous/cached-axios';
Defaults:
interpretHeader: true — honor HTTP caching headers.staleIfError: true — serve cached data when revalidation fails.ttl: 5 minutes — fallback TTL if headers don’t specify caching.No baseURL is set; pass baseURL/headers per request to keep parallel calls
safe against multiple backends.
withQuery sets a custom cache id and registers it under provided tags in
an in-memory index.withMutation builds an ACI update map ({[id]: 'delete'}) for all ids
currently associated with the given tags and clears those tag buckets.cachedAxios: ACI-wrapped Axios instance.withQuery(call, id, tags, base?): GET-like helper with stable id + tag registration.withMutation(call, invalidate, base?): write-like helper with tag-based invalidation.makeCacheHelpers(base?) → { query, mutation } bound to a base config.buildConfig(shape) → nested object with id(seg?) and tag(seg?) at every node.orvalMutator<T, R>(config, options?) → AxiosResponsecachedAxios.Id and Tag,BuiltNode, ConfigInput,await withQuery(cachedAxios.request, 'user:42', ['user:list'], {
url: '/users/42',
method: 'get',
cache: false,
});
AxiosRequestConfig['cache'] is augmented to accept false | Partial<CacheProperties>.AxiosResponse exposes cached?: boolean and previous?: AxiosResponse.CacheProperties (from ACI) is extended with id?: string, etag?: string,
and update?: Record<string, 'delete'>.npm run docs).npm test (Vitest with coverage).npm run lint.Built for you with ❤️ on Bali! Find more great tools & templates on my GitHub Profile.