Cache
The Cache
class is a core subsystem in Hyper Fetch, responsible for storing and managing response data from requests.
It provides a flexible, event-driven system for data retention, validation, and propagation throughout your application.
By default, it uses an in-memory Map
for storage, but you can easily swap in persistent storage solutions like
localStorage
or IndexedDB
.
- Store and manage request results for fast, reliable data access.
- Emit events to keep your app in sync with cache changes.
- Support flexible storage—from in-memory to persistent solutions.
- Integrate seamlessly with the Client and Request systems for a unified data flow.
Quick Start
Here's how to get started with the Cache in Hyper Fetch:
import { createClient, Cache } from "@hyper-fetch/core";
// Initialize the client with default cache
const client = createClient({ url: "http://localhost:3000" });
// Read from cache
const data = client.cache.get("key");
// Write to cache
client.cache.set("key", { data: "value" });
You can also customize the cache storage:
const client = createClient({
url: "http://localhost:3000",
cache: (instance) => new Cache(instance, { storage: localStorage }),
});
Available methods
Name | Description |
---|---|
| Update the cache data with partial response data |
| Set the cache data to the storage |
| Schedule garbage collection for given key |
| Get sync storage keys, lazyStorage keys will not be included |
| Invalidate cache by cacheKey or partial matching with RegExp It emits invalidation event for each matching cacheKey and sets staleTime to 0 to indicate out of time cache |
| |
| Used to receive data from lazy storage |
| Used to receive keys from sync storage and lazy storage |
| Used to receive keys from sync storage and lazy storage |
| Get particular record from storage by cacheKey. It will trigger lazyStorage to emit lazy load event for reading it's data. |
| Delete record from storages and trigger invalidation event |
| Clear cache storages |
Features
- Key-based storage: Data is stored and retrieved using unique cache keys, auto-generated from request details.
- Flexible storage: Use in-memory, localStorage, IndexedDB, or any compatible storage interface.
- Event-driven: Emits events on cache changes for real-time updates.
- Persistence: Easily enable persistent cache across sessions.
- Fine-grained control: Read, write, update, delete, and invalidate cache entries with simple methods.
- Integration: Works seamlessly with the Client and Request systems.
How it works
The cache stores data on a key-value basis. The key (usually cacheKey
) is auto-generated from the request's
method, endpoint, and query params, but you can override it for advanced scenarios.
const getUsers = client.createRequest()({
method: "GET",
endpoint: "/users",
});
// get data by cache key
const data = client.cache.get(getUsers.cacheKey);
// or directly by request instance
const data = getUsers.read();
You can also set a custom cache key:
const getUsers = client.createRequest()({
method: "GET",
endpoint: "/users",
cacheKey: "CUSTOM_CACHE_KEY",
});
// get data by custom cache key
const data = client.cache.get("CUSTOM_CACHE_KEY");
// or directly by request instance
const data = getUsers.read();
CacheKey
The cacheKey
is a unique identifier for the cache entry. By default it is auto-generated from the request's endpoint,
url params and query params but you can still add the key manually when setting the Request or generic generator.
const getUser = client.createRequest()({
method: "GET",
endpoint: "/users/:userId",
});
const cacheKey = getUser.cacheKey; // "/users/:userId"
const cacheKeyWithParams = getUser.setParams({ userId: 1 }).cacheKey; // "/users/1"
const cacheKeyWithQueryParams = getUser.setQueryParams({ page: 1 }).cacheKey; // "/users/:userId?page=1"
Custom cacheKey
You can also set a custom cache key:
import { client } from "./api";
const getUser = client.createRequest()({
method: "GET",
endpoint: "/users/:userId",
cacheKey: "CUSTOM_CACHE_KEY",
});
console.log(getUser.cacheKey); // "CUSTOM_CACHE_KEY"
Generic cacheKey
You can also set a generic cache key:
import { client } from "./api";
client.setCacheKeyMapper((request) => {
if (request.requestOptions.endpoint === "/users/:userId") {
return `CUSTOM_CACHE_KEY_${request.params?.userId || "unknown"}`;
}
});
const getUser = client.createRequest()({
method: "GET",
endpoint: "/users/:userId",
});
console.log(getUser.setParams({ userId: 1 }).cacheKey); // "CUSTOM_CACHE_KEY_1"
Quick Start
-
Reading from Cache
Use the get
method to read data stored under a given key:
const data = client.cache.get("key");
Or with a request instance:
const getNote = client.createRequest<{ response: Note }>()({
method: "GET",
endpoint: "/notes/:noteId",
});
const data = getNote.setParams({ noteId: 1 }).read();
console.log(data); // Note or undefined
-
Writing to Cache
Use the set
method to store data under a given key. Pass the request instance to ensure correct configuration:
const getNote = client.createRequest()({
method: "GET",
endpoint: "/notes/:noteId",
});
client.cache.set(getNote.setParams({ noteId: 1 }), {
data: { text: "Hello World" },
error: null,
status: 200,
success: true,
extra: xhrExtra,
});
-
Updating Cache
Update existing cache entries with the update
method. The cache will not update if the initial data is missing.
Cache will NOT update if the initial data is not present in the cache.
client.cache.update(getNote.setParams({ noteId: 1 }), {
data: { text: "Hello World" },
error: null,
status: 200,
success: true,
extra: xhrExtra,
});
// Or with a callback
client.cache.update(getNote.setParams({ noteId: 1 }), (prevData) => ({
...prevData,
data: { text: "Hello World" },
}));
-
Deleting from Cache
Remove data from the cache using the delete
method:
client.cache.delete(getNote.setParams({ noteId: 1 }).cacheKey);
// OR
client.cache.delete("CUSTOM_CACHE_KEY");
-
Invalidating Cache
Invalidate cache entries with the invalidate
method. This sets the staleTime
to 0, so the next request will refetch
the data. It also emits an event, triggering refetching in dedicated frameworks integrations like for example in React.
client.cache.invalidate(getNote.setParams({ noteId: 1 }).cacheKey);
// OR
client.cache.invalidate("CUSTOM_CACHE_KEY");
// OR via RegExp
client.cache.invalidate(new RegExp("CUSTOM_CACHE_KEY"));
Persistence
Enable persistent cache by providing a compatible storage interface (e.g., localStorage, IndexedDB):
const client = createClient({
url: "http://localhost:3000",
cache: (instance) => new Cache(instance, { storage: localStorage }),
});
Currently, there is no cross-tab synchronization. This is planned for a future release.
Events & Lifecycle
The cache emits events on changes, allowing you to react to updates in real time. See all available events:
Name | Type | Description |
---|---|---|
emitCacheData |
| Set cache data |
emitDelete |
| Delete of cache values |
emitInvalidation |
| Invalidate cache values event |
onData |
| Cache data listener |
onDataByKey |
| Cache data listener |
onDelete |
| |
onDeleteByKey |
| |
onInvalidate |
| Cache invalidation listener |
onInvalidateByKey |
| Cache invalidation listener |
Configuration Options
You can configure the cache with various options:
Name | Type | Description |
---|---|---|
lazyStorage |
| Lazy loading from remote resources - possibly persistent |
storage |
| Assign your custom sync storage |
version |
| Key to clear lazy storage data, often used for versioning If the new key is different from the old one, the cache will be cleared |
TypeScript
The Cache system is fully typed and integrates with your Client and Request types. When using TypeScript, you get full type safety for cache operations, including data, error, and extra fields.
const getUser = client.createRequest<{ response: { name: string } }>()({ endpoint: "/users/:id" });
const data = getUser.setParams({ id: 1 }).read();
console.log(data); // { name: string }