Skip to content

Commit

Permalink
refactor: axios.defaults.cache required
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurfiorette committed Sep 10, 2021
1 parent ed1e585 commit 29d79d5
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 58 deletions.
11 changes: 6 additions & 5 deletions src/axios/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
2 changes: 2 additions & 0 deletions src/axios/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './cache';
export * from './types'
108 changes: 61 additions & 47 deletions src/axios/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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 {
Expand All @@ -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 }>;
Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { createCache } from './axios/cache';
export * from './constants';
export * from './axios';
export * as Constants from './constants';
export * from './storage';
2 changes: 1 addition & 1 deletion src/interceptors/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions src/interceptors/response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
1 change: 0 additions & 1 deletion src/storage/memory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 29d79d5

Please sign in to comment.