Closed speyou closed 5 years ago
Sorry for the delay, and thanks for your nice comment! Your question may related with this issue https://github.com/kuitos/axios-extensions/issues/37 Feel free to ask any questions!
No problem for the delay, thanks very much for your answer! I tried to play with a customAdapter on top of yours but I don't find a way to: a) prevent the deletion of the cached result b) make another call to the cache
function customAdapter(adapter) {
return async config => {
try {
// I think cache.del(index) will be called here anyway
return await adapter(config);
} catch (e) {
if (e.request && e.request.status === 0) {
// how to call cacheAdapterEnhancer again and cache.get(index)?
}
throw e;
}
};
}
export const http = axios.create({
// setup default URL
baseURL: API_URL,
headers: { "Cache-Control": "no-cache" },
adapter: cacheAdapterEnhancer(customAdapter(axios.defaults.adapter))
});
You can make a request interceptor which returns the previous cache while in 'offline mode'. here is minimal example you can refer to:
import { Cache, cacheAdapterEnhancer } from 'axios-extensions'
import buildSortedURL from 'axios-extensions/lib/utils/buildSortedURL'
const cache = new Cache();
export const http = axios.create({
// setup default URL
baseURL: API_URL,
headers: { "Cache-Control": "no-cache" },
adapter: cacheAdapterEnhancer(axios.defaults.adapter, { defaultCache: cache }))
});
http.interceptors.request.use(config => config, error => {
if (inOfflineMode) {
const { url, params, paramsSerializer } = errror.config
const index = buildSortedURL(url, params, paramsSerializer)
return cache.get(index)
}
return Promise.reject(error)
})
Thanks for your most precious help! Since I'm using default caching + forceUpdate (in order to use cache ONLY in the event of lost connection), I had to resort to a different process. I'm now using two caches: the default one (as you suggested above) and an "offline cache" that will allow the first timeout call to be answered with cache (because the default cache will delete anyway after the timeout).
If I can use some of your time again, can you give your opinion about this? Especially performance wise, is it okay to have 2 caches? (the offline one being longer in time but shorter in size).
// https://github.com/kuitos/axios-extensions
import buildSortedURL from "axios-extensions/lib/utils/buildSortedURL";
import { Cache } from "axios-extensions";
// the defaultCache used by axios
import { cache } from "../plugins/http";
import ConnectionService from "../services/connection.service";
const TWENTY_MINUTES = 1000 * 60 * 20;
const CAPACITY = 20;
export const offlineCache = new Cache({ maxAge: TWENTY_MINUTES, max: CAPACITY });
export function offlineRequestInterceptor(config) {
// since cache is enabled by default
// we need to specify forceUpdate
// in order to always get the latest data from server
config.forceUpdate = true;
// in case of offline, we stop updating
// and return the cached result instead
if (ConnectionService.isOffline() === true) {
config.forceUpdate = false;
}
return config;
}
export function offlineResponseInterceptor(response) {
const { method, url, params, paramsSerializer } = response.config;
// we cache only get methods and don't cache offline results
if (method === "get" && ConnectionService.isOffline() === false) {
// we get the unique key needed for the cache
const index = buildSortedURL(url, params, paramsSerializer);
// and we set the offline cache
offlineCache.set(index, cache.get(index));
}
return response;
}
export async function offlineResponseErrorInterceptor(error) {
// error.request is an instance of XMLHttpRequest
const status = error.request && error.request.status;
// be sure it's a couldn't reach server error (status 0)
// and of course not already offline
if (status === 0 && ConnectionService.isOffline() === false) {
// we await the answer in order to be able to use the following lines
await ConnectionService.checkOfflineStatus();
}
// is the app offline?
if (ConnectionService.isOffline() === true) {
const { method, url, params, paramsSerializer } = error.config;
// get the cached version (if any)
if (method === "get") {
const index = buildSortedURL(url, params, paramsSerializer);
// the beauty of it reside in the fact that
// requests won't fail if cached by regular cache
// so offline cache will get useful only for the first few timeout-pending requests
return offlineCache.get(index);
}
}
// if error is not handled yet, we return falty promise
return Promise.reject(error);
}
And somewhere else:
httpInstance.interceptors.request.use(offlineRequestInterceptor);
httpInstance.interceptors.response.use(offlineResponseInterceptor, offlineResponseErrorInterceptor);
Awesome workaround! From my rough review, the advice is that u could use the native web api to check the offline status, such as navigator.onLine, and remove the offlineResponseInterceptor interceptor.
export function offlineRequestInterceptor(config) {
// since cache is enabled by default
// we need to specify forceUpdate
// in order to always get the latest data from server
config.forceUpdate = true;
// in case of offline, we stop updating
// and return the cached result instead
if (navigator.onLine === false) {
config.forceUpdate = false;
const index = buildSortedURL(url, params, paramsSerializer);
offlineCache.set(index, cache.get(index));
}
return config;
}
export async function offlineResponseInterceptor(error) {
// error.request is an instance of XMLHttpRequest
const status = error.request && error.request.status;
if (navigator.onLine === false) {
const { method, url, params, paramsSerializer } = error.config;
// get the cached version (if any)
if (method === "get") {
const index = buildSortedURL(url, params, paramsSerializer);
// the beauty of it reside in the fact that
// requests won't fail if cached by regular cache
// so offline cache will get useful only for the first few timeout-pending requests
return offlineCache.get(index);
}
}
// if error is not handled yet, we return falty promise
return Promise.reject(error);
}
And, if you do not wanna enable the cache by default, you could use the config like below to instead of forceUpdate setting:
adapter: cacheAdapterEnhancer(axios.defaults.adapter, { enabledByDefault: false }))
For more information u could check the api doc https://github.com/kuitos/axios-extensions#cacheadapterenhancer
If I don't enabledByDefault I witnessed it won't cache anything. I want it to cache but I don't want it to access this cache unless its offline.
Anyway you answered my doubts and I have a neat feature thanks to you now, we can close. :)
Hi, first I want to say this is an awesome lib! Thanks for sharing. I'm not sure I am using it well in the following scenario: 1- cache all requests 2- forceUpdate all requests in order to have the latest data from server 3- if a request fails because of lost connection, I start a so called "offline mode" and set forceUpdate to false 4- I can use my app offline if I go on all the places I already went to (because they are cached) 5- all the places BUT the first one, the one that failed at step 3. It's either not cached or cached with failure. Even if I had it cached previously, I lost the data.
My question is: is it possible to keep the cache even if the axios call is rejected?