Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for caching GET requests #31

Closed
mzabriskie opened this issue Dec 11, 2014 · 18 comments
Closed

Add support for caching GET requests #31

mzabriskie opened this issue Dec 11, 2014 · 18 comments
Milestone

Comments

@mzabriskie
Copy link
Member

Will implement using https://github.com/mzabriskie/felix

@mzabriskie mzabriskie added this to the 0.6.0 milestone Mar 19, 2015
@ericclemmons
Copy link

Heh, I was just looking into this! I thought that an interceptor could be used or a transformer that'll immediately resolve with a response, but no such luck yet.

Felix looks interesting for sure...

@englercj
Copy link

👍 The node version isn't super useful for me until we have a plugable caching layer.

@cezarsmpio
Copy link

Any progress in browser? The cache working?

@thebigredgeek
Copy link

Bump... need this or I am going to swap out axios for superagent or request for our production app... causes huge slowdowns

@clayreimann
Copy link

clayreimann commented Jun 28, 2016

@mzabriskie I've added support for ttls in mzabriskie/felix#4 and can tackle this if you like my implementation there.

@mccxiv
Copy link

mccxiv commented Jul 2, 2016

Glad to see this issue being revived, it would save me from having to write a bunch of boilerplate 😄

@rubennorte
Copy link
Member

rubennorte commented Jul 8, 2016

I think right now caching can be implemented via interceptors, although it's not very clean:

cache(axios, options);

function cache(instance, options) {
  instance.interceptors.request.use(function(config) {
    if (!config.method === 'get') {
      return config;
    }
    return cache.get(generateOptions(config, options))
      .then(createCachedError, function() { return config; });
  });
  instance.interceptors.response.use(null, function(error) {
    if (error.cachedResult) {
      return Promise.resolve(error.cachedResult);
    }
    return Promise.reject(error);
  });
}

A cleaner way to do this could be defining the default adapter (http, xhr) in the instance defaults and then using a custom adapter like this:

axios.get('url', { adapter: cachingAdapter });

function cachingAdapter(resolve, reject, config) {
  cache.get(generateOptions(config, options)).then(function(result) {
    resolve(createResponse(result));
  }, function() {
    axios.defaults.adapter(resolve, reject, config);
  });
}

I also think that adapters should return promises instead of getting the resolve and reject methods, but that's not an issue right now.

I think Axios should leave caching out of the core and allow an implementation like this.

What do you think?

@rubennorte
Copy link
Member

I'm closing this issue due to inactivity. Feel free to reopen it if you consider it requires further discussion ;)

@cristian-eriomenco
Copy link

Is there a solution for this? It seems odd that there is no obvious way onto caching requests...

@john1jan
Copy link

john1jan commented Feb 2, 2017

@rubennorte what is options in cache(axios, options); ?

@rubennorte
Copy link
Member

rubennorte commented Feb 2, 2017

@john1jan hypothetical options for the cache client you use. For example, options for a catbox client.

@jnv
Copy link

jnv commented Mar 17, 2017

Depending on your use case, you can just override get function:

// Create intercepting get function which returns cached promise,
// hence multiple requests to the same URL will be resolved by
// a single promise.
function cachingGet (get) {
  const cache = new Map()

  return function cachedGet (url) {
    const key = url

    if (cache.has(key)) {
      return cache.get(key)
    } else {
      const request = get(...arguments)
      cache.set(key, request)
      return request
    }
  }
}

const instance = axios.create(config)
instance.get = cachingGet(instance.get)

@Rebolon
Copy link

Rebolon commented Apr 3, 2017

maybe a better solution would be using adpater pattern ?

@ghost
Copy link

ghost commented Sep 18, 2017

Made a thing for this https://github.com/RasCarlito/axios-cache-adapter :)
I released a first version but it needs more testing. Hope it can be useful for others.
I'm going to implement it in a big project for one of my clients.

By default it uses an in memory custom store for the cache.
In browsers it can receive a Promisified localStorage instance like localForage.
I haven't explored for an equivalent solution in Node.

Example:

import axios from 'axios'
import { setupCache } from 'axios-cache-adapter'

const cache = setupCache(/* options */)
const api = axios.create({
  adapter: cache.adapter
})

api.get('some-url').then(response => /* Do something awesome with response.data \o/ */)

Cheers 🍻

@kuitos
Copy link
Contributor

kuitos commented Oct 18, 2017

I have made a set of extensions for axios, including caching GET request, which depends on axios custom adapter mechanism and lru-cache, and the most important thing is the test coverage has reached 100% 🎉. https://github.com/kuitos/axios-extensions

Example

import axios from 'axios';
import { cacheAdapterEnhancer } from 'axios-extensions';

const http = axios.create({
	baseURL: '/',
	headers: { 'Cache-Control': 'no-cache' },
	// cache will be enabled by default
	adapter: cacheAdapterEnhancer(axios.defaults.adapter)
});

http.get('/users'); // make real http request
http.get('/users'); // use the response from the cache of previous request, without real http request made
http.get('/users', { cache: false }); // disable cache manually and the the real http request invoked

btw, I have made another powerful extension, which can throttle the requests in the threshold time.

import axios from 'axios';
import { throttleAdapterEnhancer } from 'axios-extensions';

const http = axios.create({
	baseURL: '/',
	headers: { 'Cache-Control': 'no-cache' },
	adapter: throttleAdapterEnhancer(axios.defaults.adapter, 2 * 1000)
});

http.get('/users'); // make real http request
http.get('/users'); // responsed from the cache
http.get('/users'); // responsed from the cache

for more information u can check the api doc

Hope that can be useful for u and feel free to ask any questions🙂

@anthlasserre
Copy link

To people just want to disable cache I used:
const config = { headers: {'Content-Type': 'application/json','Cache-Control' : 'no-cache'}};
and call my api like this:
const { data } = await axios.get('http://www.youraddress.com/api/data.json', config);

@vintesh
Copy link

vintesh commented Oct 15, 2018

How about this in TypeScript [can easily be a JS thing] -

export class AxiosFactory {

    private static CACHE_MAP = new Map<string, AxiosResponse>();

    private static attachTokenToURL(config): AxiosFactory {
        let urlToUse = config.url;
        // Custom Token Attachment
        return config;
    }

    private static cachingAdapter(config: AxiosRequestConfig): AxiosPromise<AxiosResponse<any>> {
        if (!!AxiosFactory.CACHE_MAP.get(config.url)) {
            return new Promise((resolve, reject) => {
                resolve(AxiosFactory.CACHE_MAP.get(config.url));
            });
        } else {
            return axios.defaults.adapter(config);
        }
    }

    static GetAxiosConfig(baseUrl, enableCaching = false) {
        let defaultConfig = {
            baseURL: baseUrl,
            headers: { "Authorization": TokenService.GetTokenValue() } //optional
        } as AxiosRequestConfig;

        if (enableCaching) {
            defaultConfig.adapter = AxiosFactory.cachingAdapter
        }
        const instance = axios.create(defaultConfig);

        // Only for Adding Tokens in here.
        instance.interceptors.request.use((config) => {
            config = AxiosFactory.attachTokenToURL(config);
            return config;
        }, (error) => {
            return Promise.reject(error);
        });

        // Only for catching Caches
        instance.interceptors.response.use((response) => {
            AxiosFactory.CACHE_MAP.set(response.request.responseURL, response);
            return response;
        }, (error) => {
            return Promise.reject(error);
        });

        return instance;
    }
}

@marxyes
Copy link

marxyes commented Apr 23, 2020

const config = { headers: {'Content-Type': 'application/json','Cache-Control' : 'no-cache'}};

Request URL: http://myurl
Referrer Policy: no-referrer-when-downgrade
Provisional headers are shown
Accept: application/json, text/plain, /
ApiKey: myapikey
Cache-Control: no-cache
Referer: http://localhost:3000/orders
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36

it causing issue when request with 'Cache-Control' : 'no-cache' in header .
how can I implement cache-control in my axios instance .

My Code:

const instance = axios.create({baseURL: url});

instance.defaults.headers['ApiKey'] = key;
instance.defaults.headers['Cache-Control'] = "no-cache";

I have also tried your solution passing config in single request . but no luck.

what will be the solution?

@axios axios locked and limited conversation to collaborators May 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests