refactor: axios.defaults.cache required

This commit is contained in:
Hazork 2021-09-10 09:54:30 -03:00
parent ed1e5853af
commit 29d79d5c84
7 changed files with 74 additions and 58 deletions

View File

@ -3,15 +3,16 @@ import { applyRequestInterceptor } from '../interceptors/request';
import { applyResponseInterceptor } from '../interceptors/response';
import { MemoryStorage } from '../storage/memory';
import { defaultKeyGenerator } from '../utils/key-generator';
import { AxiosCacheInstance, CacheInstance, CacheRequestConfig } from './types';
import { AxiosCacheInstance, CacheInstance, CacheProperties } from './types';
type Options = CacheRequestConfig['cache'] & Partial<CacheInstance>;
export function createCache(axios: AxiosInstance, options: Options = {}): AxiosCacheInstance {
export function createCache(
axios: AxiosInstance,
options: Partial<CacheInstance & CacheProperties> = {}
): AxiosCacheInstance {
const axiosCache = axios as AxiosCacheInstance;
axiosCache.storage = options.storage || new MemoryStorage();
axiosCache.generateKey = defaultKeyGenerator;
axiosCache.generateKey = options.generateKey || defaultKeyGenerator;
// CacheRequestConfig values
axiosCache.defaults = {

2
src/axios/index.ts Normal file
View File

@ -0,0 +1,2 @@
export * from './cache';
export * from './types'

View File

@ -8,6 +8,57 @@ import type {
} from 'axios';
import { CacheStorage } from '../storage/types';
export type DefaultCacheRequestConfig = AxiosRequestConfig & {
cache: Required<CacheProperties>;
};
export type CacheProperties = {
/**
* The time until the cached value is expired in milliseconds.
*
* @default 1000 * 60 * 5
*/
maxAge?: number;
/**
* If this interceptor should configure the cache from the request cache header
* When used, the maxAge property is ignored
*
* @default false
*/
interpretHeader?: boolean;
/**
* All methods that should be cached.
*
* @default ['get']
*/
methods?: Lowercase<Method>[];
/**
* The function to check if the response code permit being cached.
*
* @default ({ status }) => status >= 200 && status < 300
*/
shouldCache?: (response: AxiosResponse) => boolean;
/**
* Once the request is resolved, this specifies what requests should we change the cache.
* Can be used to update the request or delete other caches.
*
* If the function returns void, the entry is deleted
*
* This is independent if the request made was cached or not.
*
* The id used is the same as the id on `CacheRequestConfig['id']`, auto-generated or not.
*
* @default {}
*/
update?: {
[id: string]: 'delete' | ((oldValue: any, atual: any) => any | void);
};
};
/**
* Options that can be overridden per request
*/
@ -23,52 +74,7 @@ export type CacheRequestConfig = AxiosRequestConfig & {
/**
* All cache options for the request
*/
cache?: {
/**
* The time until the cached value is expired in milliseconds.
*
* @default 1000 * 60 * 5
*/
maxAge?: number;
/**
* If this interceptor should configure the cache from the request cache header
* When used, the maxAge property is ignored
*
* @default false
*/
interpretHeader?: boolean;
/**
* All methods that should be cached.
*
* @default ['get']
*/
methods?: Lowercase<Method>[];
/**
* The function to check if the response code permit being cached.
*
* @default ({ status }) => status >= 200 && status < 300
*/
shouldCache?: (response: AxiosResponse) => boolean;
/**
* Once the request is resolved, this specifies what requests should we change the cache.
* Can be used to update the request or delete other caches.
*
* If the function returns void, the entry is deleted
*
* This is independent if the request made was cached or not.
*
* The id used is the same as the id on `CacheRequestConfig['id']`, auto-generated or not.
*
* @default {}
*/
update?: {
[id: string]: 'delete' | ((oldValue: any, atual: any) => any | void);
};
};
cache?: CacheProperties;
};
export interface CacheInstance {
@ -87,11 +93,19 @@ export interface CacheInstance {
generateKey: (options: CacheRequestConfig) => string;
}
/**
* Same as the AxiosInstance but with CacheRequestConfig as a config type.
*
* @see AxiosInstance
* @see CacheRequestConfig
* @see CacheInstance
*/
export interface AxiosCacheInstance extends AxiosInstance, CacheInstance {
(config: CacheRequestConfig): AxiosPromise;
(url: string, config?: CacheRequestConfig): AxiosPromise;
defaults: CacheRequestConfig;
defaults: DefaultCacheRequestConfig;
interceptors: {
request: AxiosInterceptorManager<CacheRequestConfig>;
response: AxiosInterceptorManager<AxiosResponse & { config: CacheRequestConfig }>;

View File

@ -1,3 +1,3 @@
export { createCache } from './axios/cache';
export * from './constants';
export * from './axios';
export * as Constants from './constants';
export * from './storage';

View File

@ -20,7 +20,7 @@ export function applyRequestInterceptor(axios: AxiosCacheInstance) {
// The cache header will be set after the response has been read, until that time, the expiration will be -1
expiration: config.cache?.interpretHeader
? -1
: config.cache?.maxAge || axios.defaults.cache!.maxAge!
: config.cache?.maxAge || axios.defaults.cache.maxAge
});
return config;
}

View File

@ -48,13 +48,13 @@ export function applyResponseInterceptor(axios: AxiosCacheInstance) {
const expirationTime = maxAge
? // Header max age in seconds
Date.now() + maxAge * 1000
: response.config.cache?.maxAge || axios.defaults.cache!.maxAge!;
: response.config.cache?.maxAge || axios.defaults.cache.maxAge;
cache.expiration = expirationTime;
} else {
// If the cache expiration has not been set, use the default expiration.
cache.expiration =
cache.expiration || response.config.cache?.maxAge || axios.defaults.cache!.maxAge!;
cache.expiration || response.config.cache?.maxAge || axios.defaults.cache.maxAge!;
}
const data = { body: response.data, headers: response.headers };

View File

@ -10,7 +10,6 @@ export class MemoryStorage implements CacheStorage {
return value;
}
// Fresh copy to prevent code duplication
const empty = { data: null, expiration: -1, state: 'empty' } as const;
this.storage.set(key, empty);
return empty;