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.
buildConfig
Declaratively 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.
makeCacheHelpers
import { 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.