Request specifics
Each request can have its own cache customization, by using the cache
property. This way, you can have requests behaving differently from each other without much effort.
The inline documentation is self explanatory, but here is a shortly brief of what each property does:
TIP
You can override every request specific property when creating the cached axios client, the same way you do with the global options.
id
optional- Type:
string
- default: (auto generated by the current key generator)
The Request ID used in this request.
It may have been generated by the Key Generator or a custom one provided by config.id
cache
optional- Type:
false
orPartial<CacheProperties<R, D>>
. - Default:
{}
(Inherits from global configuration)
TIP
As this property is optional, when not provided, all properties will inherit from global configuration
The cache option available through the request config is where all the cache customization happens.
Setting the cache
property to false
will disable the cache for this request.
This does not mean that the cache will be excluded from the storage, in which case, you can do that by deleting the storage entry:
// Make a request with cache disabled.
const { id: requestId } = await axios.get('url', { cache: false });
// Delete the cache entry for this request.
await axios.storage.remove(requestId);
cache.ttl
optional- Type:
number
- Default:
1000 * 60 * 5
(5 Minutes)
WARNING
When using interpretHeader, this value will only be used if the interpreter can’t determine their TTL value to override this one.
The time until the cached value is expired in milliseconds.
If a function is used, it will receive the complete response and waits to return a TTL value
cache.interpretHeader
optional- Type:
boolean
- Default:
true
TIP
You can override the default behavior by changing the headerInterpreter option.
If activated, when the response is received, the ttl
property will be inferred from the requests headers. As described in the MDN docs and HTML specification.
See the actual implementation of the interpretHeader
method for more information.
cache.cacheTakeover
optional- Type:
boolean
- Default:
true
As most of our cache strategies depends on well known defined HTTP headers, most browsers also use those headers to define their own cache strategies and storages.
This can be seen when opening network tab in your browser’s dev tools.
When your requested routes includes Cache-Control
in their responses, you may end up with we and your browser caching the response, resulting in a double layer of cache.
This option solves this by including some predefined headers in the request, that should tell any client / adapter to not cache the response, thus only we will cache it.
These are headers used in our specific request, it won’t affect any other request or response that the server may handle.
Headers included:
Cache-Control: no-cache
Pragma: no-cache
Expires: 0
WARNING
This option will not work on most CORS requests, as the browser will throw Request header field pragma is not allowed by Access-Control-Allow-Headers in preflight response.
.
When you encounter this error, you need to make sure Cache-Control
, Pragma
and Expires
headers are included into your server’s Access-Control-Allow-Headers
CORS configuration.
If you cannot do such thing, you can fallback to disabling this option. Learn more on why it should be enabled at #437 and in this StackOverflow answer.
cache.methods
optional- Type:
Method[]
- Default:
["get", "head"]
Specifies which methods we should handle and cache. This is where you can enable caching to POST
, PUT
, DELETE
and other methods, as the default is only GET
.
If you want to enable cache for POST
requests, you can do:
// Globally enables caching for POST requests
const axios = setupCache(instance, {
methods: ['get', 'post']
});
// Just for this request
axios.post('url', data, {
cache: {
methods: ['post']
}
});
We use methods
in a per-request configuration setup because sometimes you have exceptions to the method rule.
cache.cachePredicate
optional- Type:
CachePredicate<R, D>
- Default:
{ statusCheck: (status) => [200, 203, 300, 301, 302, 404, 405, 410, 414, 501].includes(status) }
(These default status codes follows RFC 7231)
An object or function that will be tested against the response to indicate if it can be cached. You can use statusCheck
, containsHeader
, ignoreUrls
and responseMatch
to test against the response.
axios.get<{ auth: { status: string } }>('url', {
cache: {
cachePredicate: {
// Only cache if the response comes with a "good" status code
statusCheck: (status) => true, // some calculation
// Tests against any header present in the response.
containsHeaders: {
'x-custom-header-3': (value) => true // some calculation
},
// Check custom response body
responseMatch: ({ data }) => {
// Sample that only caches if the response is authenticated
return data.auth.status === 'authenticated';
},
// Ensures no request is cached if its url starts with "/api"
ignoreUrls: [/^\/api/]
}
}
});
cache.update
optional- Type:
CacheUpdater<R, D>
- Default:
{}
Once the request is resolved, this specifies what other responses should change their cache. Can be used to update the request or delete other caches. It is a simple Record
with the request id.
Here’s an example with some basic login:
Using a function instead of an object is supported but not recommended, as it’s better to just consume the response normally and write your own code after it. But it`s here in case you need it.
// Some requests id's
let profileInfoId;
let userInfoId;
axios.post<{ auth: { user: User } }>(
'login',
{ username, password },
{
cache: {
update: {
// Evicts the profile info cache, because now he is authenticated and the response needs to be re-fetched
[profileInfoId]: 'delete',
// An example that update the "user info response cache" when doing a login.
// Imagine this request is a login one.
[userInfoResponseId]: (cachedValue, response) => {
if (cachedValue.state !== 'cached') {
// Only needs to update if the response is cached
return 'ignore';
}
cachedValue.data = data;
// This returned value will be returned in next calls to the cache.
return cachedValue;
}
}
}
}
);
cache.etag
optional- Type:
boolean
- Default:
true
If the request should handle ETag
and If-None-Match support
. Use a string to force a custom static value or true to use the previous response ETag.
To use true
(automatic ETag handling), interpretHeader
option must be set to true
.
cache.modifiedSince
optional- Type:
boolean
- Default:
true
Use If-Modified-Since
header in this request. Use a date to force a custom static value or true to use the last cached timestamp.
If never cached before, the header is not set.
If interpretHeader
is set and a Last-Modified
header is sent to us, then value from that header is used, otherwise cache creation timestamp will be sent in If-Modified-Since
.
cache.staleIfError
- Type:
number
orboolean
orStaleIfErrorPredicate<R, D>
- Default:
true
Enables cache to be returned if the response comes with an error, either by invalid status code, network errors and etc. You can filter the type of error that should be stale by using a predicate function.
WARNING
If the response is treated as error because of invalid status code (like when using statusCheck), and this ends up true
, the cache will be preserved over the “invalid” request.
So, if you want to preserve the response, you can use the below predicate:
const customPredicate = (response, cache, error) => {
// Blocks staleIfError if has a response
return !response;
// Note that, this still respects axios default implementation
// and throws an error, (but it keeps the response)
};
Types:
number
-> the max time (in seconds) that the cache can be reused.boolean
->false
disables andtrue
enables with infinite time if no value is present onstale-if-error
in Cache-Control.function
-> a predicate that can returnnumber
orboolean
as described above.
cache.override
optional- Type:
boolean
- Default:
false
This option bypasses the current cache and always make a new http request. This will not delete the current cache, it will just replace the cache when the response arrives.
Unlike as cache: false
, this will not disable the cache, it will just ignore the pre-request cache checks before making the request. This way, all post-request options are still available and will work as expected.
cache.hydrate
optional- Type:
undefined | ((cache: StorageValue) => void | Promise<void>)
- Default:
undefined
Asynchronously called when a network request is needed to resolve the data, but an older one and probably expired cache exists. Its with the current data BEFORE the network travel starts, so you can use it to temporarily update your UI with expired data before the network returns.
Hydrating your components with old data before the network resolves with the newer one is better than flickering your entire UI. This is even better when dealing with slower networks and persisted cache, like for mobile apps.
WARNING
If the axios call will return cached data, meaning no network will be involved, the hydrate IS NOT CALLED, as the axios promise will be resolved instantly.
// Example of function that receives data and renders into a screen
function render() {}
const response = await axios.get( 'url', {
// This is called instantly if axios needs to make a network request
cache: {
hydrate: (cache) => render(cache.data)
}
});
// After the network lookup ends, we have fresh data and can
// re-render the UI with confidence
render(response.data);