Giter Club home page Giter Club logo

axios-extensions's Introduction

axios-extensions

npm version coverage npm downloads Build Status

A non-invasive, simple, reliable collection of axios extension

Extension List

v3.x has a lot of api changes, if you are looking for v2.x doc, see here

Not working with axios v0.19.0 as its custom config bug, See axios/axios#2207.

Installing

npm i axios-extensions -S

or

yarn add axios-extensions

or

// exposed as window['axios-extensions']
<script src="https://unpkg.com/axios-extensions/dist/axios-extensions.min.js"></script>

Usage

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

// enhance the original axios adapter with throttle and cache enhancer 
const http = axios.create({
	baseURL: '/',
	headers: { 'Cache-Control': 'no-cache' },
	adapter: throttleAdapterEnhancer(cacheAdapterEnhancer(axios.defaults.adapter))
});

Enable Logging

It is highly recommended to enable the request logging recorder in development environment(disabled by default).

browser (webpack)

new webpack.DefinePlugin({
  'process.env.LOGGER_LEVEL': JSON.stringify('info')
})

node

// package.json
"scripts": {
	"start": "cross-env LOGGER_LEVEL=info node server.js"
}

API

cacheAdapterEnhancer

Makes axios cacheable

cacheAdapterEnhancer(adapter: AxiosAdapter, options: Options): AxiosAdapter

Where adapter is an axios adapter which following the axios adapter standard, options is an optional that configuring caching:

Param Type Default value Description
enabledByDefault boolean true Enables cache for all requests without explicit definition in request config (e.g. cache: true)
cacheFlag string 'cache' Configures key (flag) for explicit definition of cache usage in axios request
defaultCache CacheLike
new LRUCache({ maxAge: FIVE_MINUTES, max: 100 })
a CacheLike instance that will be used for storing requests by default, except you define a custom Cache with your request config

cacheAdapterEnhancer enhances the given adapter and returns a new cacheable adapter back, so you can compose it with any other enhancers, e.g. throttleAdapterEnhancer.

basic usage

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

custom cache flag

const http = axios.create({
	baseURL: '/',
	headers: { 'Cache-Control': 'no-cache' },
	// disable the default cache and set the cache flag
	adapter: cacheAdapterEnhancer(axios.defaults.adapter, { enabledByDefault: false, cacheFlag: 'useCache'})
});

http.get('/users'); // default cache was disabled and then the real http request invoked 
http.get('/users', { useCache: true }); // make the request cacheable(real http request made due to first request invoke)
http.get('/users', { useCache: true }); // use the response cache from previous request
custom cache typing

Note that if you are using custom cache flag and typescript, you may need to add the typing declaration like below:

import { ICacheLike } from 'axios-extensions';
declare module 'axios' {
  interface AxiosRequestConfig {
    // if your cacheFlag was setting to 'useCache'
    useCache?: boolean | ICacheLike<any>;
  }
}

more advanced

Besides configuring the request through the cacheAdapterEnhancer, we can enjoy more advanced features via configuring every individual request.

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

const http = axios.create({
	baseURL: '/',
	headers: { 'Cache-Control': 'no-cache' },
	// disable the default cache
	adapter: cacheAdapterEnhancer(axios.defaults.adapter, { enabledByDefault: false })
});

http.get('/users', { cache: true }); // make the request cacheable(real http request made due to first request invoke)

// define a cache manually
const cacheA = new Cache();
// or a cache-like instance
const cacheB = { get() {/*...*/}, set() {/*...*/}, del() {/*...*/} };

// two actual request will be made due to the different cache 
http.get('/users', { cache: cacheA });
http.get('/users', { cache: cacheB });

// a actual request made and cached due to force update configured
http.get('/users', { cache: cacheA, forceUpdate: true });

Note: If you are using typescript, do not forget to enable "esModuleInterop": true and "allowSyntheticDefaultImports": true for better development experience.

throttleAdapterEnhancer

Throttle GET requests most once per threshold milliseconds

throttleAdapterEnhancer(adapter: AxiosAdapter, options: Options): AxiosAdapter

Where adapter is an axios adapter which following the axios adapter standard, options is an optional object that configuring throttling:

Param Type Default value Description
threshold number 1000 The number of milliseconds to throttle request invocations to
cache CacheLike
new LRUCache({ max: 10 })
CacheLike instance that will be used for storing throttled requests

Basically we recommend using the throttleAdapterEnhancer with cacheAdapterEnhancer together for the maximum caching benefits. Note that POST and other methods besides GET are not affected.

throttleAdapterEnhancer(cacheAdapterEnhancer(axios.defaults.adapter))

Check David Corbacho's article to learn more details about throttle and how it differs from debounce.

basic usage

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

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

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

setTimeout(() => {
	http.get('/users'); // after 2s, the real request makes again
}, 2 * 1000);

retryAdapterEnhancer

Retry the failed request with special times

retryAdapterEnhancer(adapter: AxiosAdapter, options: Options): AxiosAdapter

Where adapter is an axios adapter which following the axios adapter standard, options is an optional that configuring caching:

Param Type Default value Description
times number 2 Set the retry times for failed request globally.

basic usage

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

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

// this request will retry two times if it failed
http.get('/users');

// you could also set the retry times for a special request
http.get('/special', { retryTimes: 3 });

axios-extensions's People

Contributors

andresmrm avatar dependabot[bot] avatar eng1n88r avatar iaarnio avatar jeremiah-snee-openx avatar kevindigo avatar kuitos avatar mengqiuleo avatar nachogarcia avatar probil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

axios-extensions's Issues

Question: How to find If data is already present in cache?

I am having 2 chache

  1. defaultCache: Expire in 5 min
  2. gribCache: Expire in 8hours

Is there any way by which I can check if data is available in gribCache. I dont want to show loader if cache is available in gribCache. To do that I have to make sure that cache is present in memory and dont show loader as it will be fast.

    const defaultCache = new LRUCache({ maxAge: AppConst.httpCacheAge });
    const gribCache = new LRUCache({ maxAge: AppConst.gribCacheAge });
    const httpClient = axios.create({
      adapter:cacheAdapterEnhancer(axios.defaults.adapter, true, "cache",  defaultCache)
    });

      return httpClient.get(url, {
                cache: customCache
                    ? gribCache
                    : true,
                timeout: (customCache === AppConst.apiCaches.gribCache
                    ? AppConst.httpRequestTimeoutsGrib
                    : AppConst.httpRequestTimeouts)
            }).then(function (response) {
                if (response) {
                    return response.data;
                } 
            }, function (err) {
                return null;
            });

Got 405 error when try to get gravatars

axios-extensions works great for all my requests except for one: get gravatars.

If I use axios only, it works well.

axios.get(
    'https://www.gravatar.com/avatar/46b999a5b1498f5ef58f767845942269?d=404', {
      responseType: 'arraybuffer'
    })
  .then(res => {
    // res.data is correct array buffer
  })
  .catch(err => {});

But if I change to

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

http.get(
    'https://www.gravatar.com/avatar/46b999a5b1498f5ef58f767845942269?d=404', {
      responseType: 'arraybuffer'
    })
  .then(res => {})
  .catch(err => {});

It will throw the error:

image

Any idea? Thanks

Use pending GET request

An idea for an enhancement to throttle or cache adapters as a flag usePendingRequest.

If there is a pending [similar] request, then the call returns a promise which will resolve the same as the current request.

An example of this need can be in a framework like React or Angular where a UserName component is mounted in 2 separate DOM locations and they both make the request to fetch user data. If they both mount within milliseconds, neither will see a cached request and start a new request. This feature would reduce simultaneous "like" requests in this situation by returning a promise for the first request made.

I'm happy to contribute this effort, please advise :-)

Typescript error using with axios 0.18.0

Building a typescript project with axios and the following code

axios.create({
  adapter: throttleAdapterEnhancer(cacheAdapterEnhancer(axios.defaults.adapter, true)),
  headers: { 'Cache-Control': 'no-cache' },
});

outputs

/issuer.ts(33,61): error TS2345: Argument of type 'AxiosAdapter' is not assignable to parameter of type 'AxiosAdapter'.
  Type 'AxiosPromise<any>' is not assignable to type 'AxiosPromise'.
    Types of property 'then' are incompatible.
      Type '<TResult1 = AxiosResponse<any>, TResult2 = never>(onfulfilled?: (value: AxiosResponse<any>) => TR...' is not assignable to type '<TResult1 = AxiosResponse, TResult2 = never>(onfulfilled?: (value: AxiosResponse) => TResult1 | P...'.
        Types of parameters 'onfulfilled' and 'onfulfilled' are incompatible.
          Types of parameters 'value' and 'value' are incompatible.
            Type 'AxiosResponse<any>' is not assignable to type 'AxiosResponse'.
              Types of property 'config' are incompatible.
                Type 'AxiosRequestConfig' is not assignable to type 'AxiosRequestConfig'. Two different types with this name exist, but they are unrelated.
                  Types of property 'adapter' are incompatible.
                    Type 'AxiosAdapter' is not assignable to type 'AxiosAdapter'. Two different types with this name exist, but they are unrelated.

The environment is as follows:

$ npm ls axios typescript
[email protected] 
โ”œโ”€โ”€ [email protected]
โ”œโ”€โ”ฌ [email protected]
โ”‚ โ””โ”€โ”€ [email protected]
โ””โ”€โ”€ [email protected]

Maybe related to #13

background update feature

When using throttle &/or cache it would be beneficial to have a
fast return Cache, but update (if possible) Cache in background as a post event.

so instead of (pseudo code):

.get('my/url')
->respond with getFromCache('my/url')

do this:

.get('my/url')
->respond with getFromCache('my/url')
send('my/url')
->updateCache with result from my/url request

ESLint issue (`root:true` is needed)

First of all, thank you for the library ๐Ÿ‘

But I got an issue while using this library in CI today:

[lint-ci] Cannot find module '/app/node_modules/axios-extensions/vuejsapp/build/webpack.base.conf.js'
[lint-ci] Error: Cannot find module '/app/node_modules/axios-extensions/vuejsapp/build/webpack.base.conf.js'
[lint-ci]     at Function.Module._resolveFilename (module.js:547:15)
[lint-ci]     at Function.Module._load (module.js:474:25)
[lint-ci]     at Module.require (module.js:596:17)
[lint-ci]     at require (internal/module.js:11:18)
[lint-ci]     at Object.exports.resolve (/app/node_modules/eslint-import-resolver-webpack/index.js:68:25)
[lint-ci]     at v2 (/app/node_modules/eslint-module-utils/resolve.js:94:23)
[lint-ci]     at withResolver (/app/node_modules/eslint-module-utils/resolve.js:99:16)
[lint-ci]     at fullResolve (/app/node_modules/eslint-module-utils/resolve.js:116:22)
[lint-ci]     at Function.relative (/app/node_modules/eslint-module-utils/resolve.js:61:10)
[lint-ci]     at remotePath (/app/node_modules/eslint-plugin-import/lib/ExportMap.js:379:30)
[lint-ci] npm ERR! code ELIFECYCLE
[lint-ci] npm ERR! errno 1

After a quick investigation, I've realized that ESLint on CI is trying to extend your config with ESLint config in my project (even though node_modules is ignored). I think it can be fixed by marking your ESLint config as root, so if your library is placed inside a dir it will not automatically extend the rules defined in the parent directory.

"eslintConfig": {
    "root": true,    // <-- ADD IT HERE PLEASE
    "extends": "shuyun",
    "rules": {
      "object-curly-spacing": "off",
      "no-process-env": "off"
    }
  },

By default, ESLint will look for configuration files in all parent folders up to the root directory. This can be useful if you want all of your projects to follow a certain convention, but can sometimes lead to unexpected results. To limit ESLint to a specific project, place "root": true inside the eslintConfig field of the package.json file or in the .eslintrc.* file at your projectโ€™s root level. ESLint will stop looking in parent folders once it finds a configuration with "root": true.

From: https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy

LRUCache is not transpiled in ESM version, so it fails uglifyJS build.

The included LRUCache uses const's, which fails when I try to process it trough Uglify - could we use a version that's properly transpiled?

Unexpected token: keyword (const) [./node_modules/axios-extensions/node_modules/lru-cache/index.js:4,0][main.legacy.js:7204,0]
Details:
    domain: [object Object]
    domainThrown: true

Cache actual data, not a promise

Using response promises as cache items makes impossible to use options like max in node-lru-cache library because size of cached item is evaluated in cache's set method, when the promise is not resolved.

getting custom cache with promise to get error

When using a cache like function, the get method if a promise returns null and no and the error in the axios adapter function.

image

example: this example i use sessionStorage but i use localforage in production

export default {
    async get (index) {
        console.log("get", index);
        const v = sessionStorage.getItem(index);
        return v;
    },
    async set (index, value) {
        const v = await value;
        console.log("set", index, v);
        sessionStorage.setItem(index, JSON.parse(JSON.stringify(v)));
    },
    del (index) {
        console.log("del", index);
        sessionStorage.removeItem(index);
    },
};

Question: how do you log along with Vue-Cli?

Hello there,

First of all thank you for your magnificient work.

I'm starting to work on a Vue SPA for the first time using Vue-Cli. I used your projet to have throttling and caching on my Ajax requests. It seems to work well but I would like to have logs on the console so my developpers can know what is happening.

I know I'm supposed to add this to my webpack.config:
new webpack.DefinePlugin({ 'process.env.LOGGER_LEVEL': JSON.stringify('info') })

So on my ".env" file I tried to put this:
LOGGER_LEVEL='info'
or even this
LOGGER_LEVEL=info

But no luck...

Do you mind to help me?

Thank you,
Denis

is it safe to combine both adapters ?

sorry may seem obvious, but is it safe to use both throttle and cache adapters ?

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

// enhance the original axios adapter with throttle and cache enhancer 
const enhancedAdapter = throttleAdapterEnhancer(cacheAdapterEnhancer(axios.defaults.adapter, true))
const http = axios.create({
	baseURL: '/',
	headers: { 'Cache-Control': 'no-cache' },
	adapter: throttleAdapterEnhancer(enhancedAdapter, 2 * 1000)
});

Add support for interceptor augmented results

In my scenario for GET requests I usually receive a 202 response with a location header, which designates that I need to poll the location for the async response until a non 202 response is returned. So I use an Axios response interceptor to basically poll for the async response until it resolves and then return the result.

Like so:

const myClient= function() {
    var client = axios.create({
        baseURL: serviceRoot+'/',
        timeout: 3000,
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        auth: {
            username,
            password
        }
    });

    /** Here we intercept responses coming from the server to check if the response is async, in which case we start polling and resolve the response the completed operation result */
    client.interceptors.response.use(async function (response) {
        if (response.headers.location) {
            var asyncResLocation = response.headers.location;
            response = await retry(async () => {
                try {
                    let asyncRes = httpParser.parseResponse((await client.get(asyncResLocation)).data); // unwrap async response
                    if (asyncRes.statusCode == 200) {
                        if (typeof asyncRes.body === 'string') {
                            let jsonRes = JSON.parse(asyncRes.body);
                            return jsonRes.value || jsoneRes;
                        }
                        return asyncRes;
                    }
                    throw new Error(asyncRes);
                }
                catch (e) {
                    throw new Error(e);
                }
            }, {
                    minTimeout: ASYNC_RESPONSE_POLLING_INTERVAL_MILLISECONDS,
                    retries: ASYNC_RESPONSE_RETRY_COUNT
                }); // End polling
            }
            return response;
        }, function (error) {
            // Do something with response error
            return Promise.reject(error);
        }
    );
    
    return client;
}

Can your awesome cache extension use the calculated result returned from the interceptor as the cache value? I tried a straight forward approach from your docs and couldn't get it to cache the interceptor return value.

Feature request: queue / rate limit requests adapter

Especially useful for web API's with a rate limit.

It's about being able to queue requests to stay below the limit rate. Or, sometimes API's methods have a nonce and might be rejected if the requests are received in a different order.

No request is dropped.

It would be possible to indicate the minimum amount of time to pass before the next request is made.

Adding a possibility to have a custom cache-key generator.

In our API calls we pass a languageid & siteid as header data, which will give us different results. For this it would be handy for us to allow passing a custom cachekey generator with the options.

Do you agree with this idea? If yes, then we can also create a Pull Request with this change if you don't have time to add it?

In throttleAdapterEnhancer & cacheAdapterEnhancer:

var customCacheKey = options.cacheKeyGenerator && options.cacheKeyGenerator(config, buildSortedURL(url, params, paramsSerializer));
var index_1 = customCacheKey || buildSortedURL(url, params, paramsSerializer);

and then in the calling method we can pass the cacheKeyGenerator to the options.

cacheAdapterEnhancer(axios.defaults.adapter, { cacheKeyGenerator: (config, originalKey) => { /*custom logic*/}});

Cache-Control header issue

I've ran into this error when specifying the headers option to include 'Cache-Control no-cache' as specified in the readme.

Failed to load resource: the server responded with a status of 404 (Not Found)
Response for preflight has invalid HTTP status code 404

The API server in question is https://api.scryfall.com , I tried some suggested workarounds online like specifying the following extra headers,

headers: { 
    'Cache-Control': 'no-cache',
    'Content-type': 'application/json',
    'Access-Control-Allow-Methods': 'GET, POST',
    'Access-Control-Allow-Headers': 'Content-type, Accept'
}

but the server still rejects requests. For now im simply not specifying Cache-Control in the HTTP client's headers, any idea how I could fix this issue?

Here is a test script you can use to duplicate the issue,

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

const api = axios.create({
	baseURL: 'https://api.scryfall.com/',
	headers: {'Cache-Control': 'no-cache'},
	adapter: cacheAdapterEnhancer(axios.defaults.adapter, true)
})

export async function searchCards(query) {
    return new Promise((resolve, reject) => {
        api.get(`cards/search?q=${query}&pretty=true`).then((res) => {
            resolve(res.data.data)
        }).catch((e) => {
            reject(e)
        })
    })
}

let cards
try {
    cards = await searchCards('wizard')
    console.log(cards)
} catch(e) {
    console.log(e)
}

How to custom cache for each APIs?

Hi guys,

Thanks for this package?

But, I have an issue with the custom cache.

Sometimes, I want to custom cache for each APIs value different.

Ex: GET /users have cache options: {maxAge: FIVE_MINUTES, max: 100}
but GET /posts have cache options {maxAge: TEN_MINUTES}

Thank you in advance.

Requests with POST is not cached

POST requests are not cached. It is requested for every request. Is there some limitation or Do I need to configure it differently?

Does not play well with 3846masa/axios-cookiejar-support

I'm creating issues on both this repo and 3846masa/axios-cookiejar-support hoping that someone either here or there will have some ideas.

Basically I have this:

const axios = require('axios')
const axiosCookieJarSupport = require('axios-cookiejar-support').default
const axiosExtensions = require('axios-extensions')
const LRUCache = require('lru-cache')

// Even tried specifying my own cookie jar
// const tough = require('tough-cookie')
// let cookiejar = new tough.CookieJar()

axiosCookieJarSupport(axios)

let cache = new LRUCache({ maxAge: 300000 })

let cacheAdapter = axiosExtensions.cacheAdapterEnhancer(axios.defaults.adapter, {
  defaultCache: cache,
  enabledByDefault: true
})

let instance = axios.create({
  adapter: cacheAdapter,
  baseURL: 'http://example.com',
  headers: {
    'Cache-Control': 'no-cache'
  },
  jar: true, // cookiejar,
  withCredentials: true
})

// Results in error
instance.get('/')
  .then(r => instance.get('/'))
  .then(r => console.log(r))
  .catch(e => console.error(e))

// This results in an error as well
// async function test() {
//   try {
//     var r1 = await instance.get('/')
//     console.log(r1)
//     var r2 = await instance.get('/')
//     console.log(r2)
//   } catch (e) {
//     console.error(e)
//   }
// }
// test()

The first request works fine (because there's not a cached version of the request) but then the second one (cached) results in the following error:

TypeError: Cannot read property 'jar' of undefined
    at /my-project/node_modules/axios-cookiejar-support/lib/interceptors/response.js:28:15
    at new Promise (<anonymous>)
    at responseInterceptor (/my-project/node_modules/axios-cookiejar-support/lib/interceptors/response.js:21:10)
    at instance.interceptors.response.use.res (/my-project/node_modules/axios-cookiejar-support/lib/index.js:47:67)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)

As soon as I remove either config.adapter or config.jar, everything works fine.

I'm having a hard time thinking of how this should even function. I guess that after the requests are cached then cookies are no longer required and should be ignored. Or maybe cached as well?

I'm going to keep playing with both packages and try to figure something out but if anyone has any ideas I'd greatly appreciate it. ๐Ÿ˜

Issue on the other repo: 3846masa/axios-cookiejar-support#157

request for Javascript

Project looks great! This request is for .js (ES6 or ES5) files to committed into /dist subdirectory, for direct use in Javascript projects.

IE error

getting Syntax error
Syntax error
bundle.js (1377,24)

const naiveLength = () => 1

Working fine in chrome and Edge.

TypeScript: module '...lru-cache' has no default export

Hello, as of today, with the latest version of both axios extensions and lru-cache, I get the following error while compiling with typescript:

ERROR in /.../node_modules/axios-extensions/lib/index.d.ts(6,8):
TS1192: Module '"/.../node_modules/@types/lru-cache/index"' has no default export.
Version: typescript 2.9.2

And it indeed is true; I had to change line

import Cache from 'lru-cache';
to
import {Cache} from 'lru-cache';

And it compiles succesfully.

Vue with TypeSctipt with axios

Having troubles with setting up caching with axios-extensions:

main.ts

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

axios.defaults.baseURL = process.env.VUE_APP_API_BASE_URL;
axios.defaults.params = {
	client_id: process.env.VUE_APP_CLIENT_ID,
	client_secret: process.env.VUE_APP_CLIENT_SECRET
};
axios.defaults.adapter = cacheAdapterEnhancer(axios.defaults.adapter);

Last line throws

Argument of type 'AxiosAdapter | undefined' is not assignable to parameter of type 'AxiosAdapter'.
Type 'undefined' is not assignable to type 'AxiosAdapter'.ts(2345)

And

Service.ts

import axios from 'axios';
import { IResponse } from './models/ResponseModel';

class Foo {
	private ACTION_URL: string = '/api/action';

	public async Bar(query: string): Promise<IResponse> {
		return await axios
			.get<IResponse>(this.ACTION_URL, {
				cache: false,
			})
			.then((response) => {
				return response.data;
			})
			.catch((error: any) => {
				return error;
			});
	}
}

Throws

Argument of type '{ cache: boolean; }' is not assignable to parameter of type 'AxiosRequestConfig'.
Object literal may only specify known properties, and 'cache' does not exist in type 'AxiosRequestConfig'

Pass arguments to adapters as object

It might be better to pass arguments to adapters as an object.
I mean, instead of:

cacheAdapterEnhancer(adapter, false, 'cache', new LRUCache({ maxAge: FIVE_MINUTES }))

use

const options = { cacheEnabledByDefault: false, enableCacheFlag: 'cache', defaultCache: new LRUCache({ maxAge: FIVE_MINUTES }) };
cacheAdapterEnhancer(adapter, options)

Advantages:

1) easier to use default values of given params
For example, currently if I want to pass only custom cache I have to define all other arguments as undefined. And it looks weird:

const cache =  new LRUCache({ maxAge: 1000 * 60 * 10 })
cacheAdapterEnhancer(axios.defaults.adapter, undefined, undefined, cache);
// compare with
cacheAdapterEnhancer(axios.defaults.adapter, { defaultCache: cache });

2) more explicit (self-descriptive) arguments

cacheAdapterEnhancer(axios.defaults.adapter, false); // <-- what's false here?
// compare with
cacheAdapterEnhancer(axios.defaults.adapter, { cacheEnabledByDefault: false } );

It's hard to recognize what is false without checking the docs. It is not good developer experience

What do you think about that @kuitos ?

Logging

Hi there

Currently, the only way to remove the log output from this module is to set NODE_ENV to production.
Moreover, axios is expected to run in Node.js and in browsers: I don't think there is a way to set such a variable in the later environment.

Could we consider using the debug package instead of console.log ?
(See https://github.com/visionmedia/debug#browser-support)

Cache a timeout request

Hi,

Is it possible to cache a request, even when the validateStatus return false or when you got a timeout ? I need to save this state to not have thousands of timed out requests in my heroku backlog. I use your extension to handle a status website for a AAA game.

Thanks.

Implement CHANGELOG.md for future releases

Hi, great library!

I wanted to suggest/request the use of a CHANGELOG.md file at the root of the repo that outlines changes (breaking, features, fixes, etc.) between releases ๐Ÿ‘

CORS error when accessed from localhost

I am getting Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin. even though I have access-control-allow-origin * present in the response.

It is working fine without axios-extensions

Failed call disappears from the cache

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?

allow forceUpdate on `POST` requests

would it be possible to allow a forceUpdate (or clear the cache for that matter) to happen on a Post/Put/Delete request? that way if you do simply just local state updates when adding/updating/deleting on the ui but if the component were to mount again, it would see that the cache is no longer there and make the API request to generate a new cache

cache OPTIONS request?

Hi, I would like to cache OPTIONS calls along with GET requests. Is it possible?
If I understand correctly, currently the cache is only enabled if method === 'get' . However I think it's a common use case to cache OPTIONS requests as well.

Persistent cache

Is it currently possible to use this library as a persistent cache ? Meaning that, after restarting the application, the cache can be loaded into memory and directly reused ?
I would need something like this in my current node project .

Using this with axios in the browser

Hey,

If I am working with a site that is using the pre-built axios (on the window) is it possible to use this?

I notice this is no dist/ directory or the likes so thought I would ask here before I start digging.

Cheers.

react-native

Hi,

I would like to know if cacheAdapterEnhancer will work in react-native.

Thanks for reply.

forceUpdate does not work with axios 0.19

I'm using request options to force axios-extensions to update cache entries when needed.

This has been working fine with axios 0.18.0 (and 0.18.1) but when I recently updated to 0.19.0 I noticed that forceUpdate does not have effect anymore. Data is still returned from cache.

package.json:

    "axios": "^0.19.0",
    "axios-extensions": "^3.0.6",

Code:

const requestOptions = {
  params: {
    _format: 'json',
  },
  forceUpdate: cacheIsBypassed,
};
const {data} = await cachedAxios.get(requestUrl, requestOptions);

For now the resolution was reverting back to 0.18.1 but for going forward it would be good to make axios-extensions to work fully with axios 0.19 too.

Getting error while using useCache flag

axios.ts file
const axiosAppInstance = axios.create({
// @ts-ignore
adapter: cacheAdapterEnhancer(axios.defaults.adapter, { enabledByDefault: false, cacheFlag: 'useCache'}),
baseURL: appConfig.getRequired('abc'),
});

abc.ts file
axiosAppInstance.get('xyz',{ useCache: true }),

TypeScript error
Argument of type '{ useCache: boolean; }' is not assignable to parameter of type 'AxiosRequestConfig'.
Object literal may only specify known properties, and 'useCache' does not exist in type 'AxiosRequestConfig'.ts

Different TTL's for individual requests?

Is there a way to set different ttl's for individual requests?

Seems like setting one maxAge for all items in the cache isn't ideal.
It would be nice if there was a way to do something like the following:

  1. Set when making the request ( I know I want this to only persist for X time so do that )
  2. Use Cache-control header max-age value - age (The server knows best, so respect that)
  3. Use default maxAge, (I didn't set anything and the server told me nothing so cache for default time)

Thoughts?

cacheFlag not working in react native

When I use CacheFlag to control caching, CacheFlag is not working in react native as expected. config[cacheFlag] is always undefined in cacheAdapterEnhancer.js. Hence it is not caching

My code is as below

const axiosClient = axios.create({
baseURL: HOST,
headers: {
'Content-type': 'application/json',
'Cache-Control': 'no-cache'
},
adapter: cacheAdapterEnhancer(axios.defaults.adapter, { enabledByDefault: false, cacheFlag: 'useCache'})
});

then in a function
return await axiosClient.get(URL, params, {useCache : true});

If i change in cacheAdapterEnhancer.js

var useCache = (config[cacheFlag] !== void 0 && config[cacheFlag] !== null) ? config[cacheFlag] : enabledByDefault;

to

var useCache = (cacheFlag !== void 0 && cacheFlag !== null) ? cacheFlag : enabledByDefault;

Now the flag works as expected. Kindly help with the issue

changing cached object issue

Hi, if you have 2 components and one of them is doing some modification on retrieved data, modification is reflected in other component.

reduce the production size

I saw the package only uses isEmpty from lodash.
So maybe just install lodash.isempty instead of lodash?

Or use own function something like

function isEmpty(obj) {
  if (!obj) return true;
  return !Object.keys(obj).length;
}

It will help reduce the production size.

The package is awesome! Very easy to use. Thank you!

Use axios paramsSerializer.

I currently set qs as axios.defaults.paramsSerializer so I can use nested parameters. These extensions do not respect the serializer and are hardcoded to use querystring.

Make extensions more browser-friendly

This is a simple, useful extension that I would love to use. However, it is not very browser friendly for these reasons:

  • has an unnecessarily large footprint with the dependency on Lodash for the use of a simple isEmpty method, which only needs to validate simple object types.
  • Dependency on node modules url and querystring for other similarly simple tasks.

I propose that all of the above functions be replaced with lightweight, browser friendly alternatives.

Expose underlying cache or some other means of explicitly clearing the cache

Feature Request

It would be useful to allow clients to explicitly clear the cache in cases where data has become stale. This could be easily achieved by exposing the cache on the wrapped adapter, but would change the API slightly.

e.g.

const cache = new LRUCache({ maxAge: cacheAge });

return {
  cache,
  adapter: config => {

		const { url, method, params } = config;
...

usage:

const cacheAdapter = cacheAdapterEnhancer(axios.defaults.adapter, true)
const http = axios.create({
	baseURL: '/',
	headers: { 'Cache-Control': 'no-cache' },
	adapter: cacheAdapter.adapter
});
...
cacheAdapter.cache.reset()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.