Skip to content

Commit

Permalink
feat: better cache predicate
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurfiorette committed Sep 11, 2021
1 parent d2c2a56 commit 892dab4
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/axios/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function createCache(
maxAge: 1000 * 60 * 5,
interpretHeader: false,
methods: ['get'],
shouldCache: ({ status }) => status >= 200 && status < 300,
cachePredicate: ({ status }) => status >= 200 && status < 300,
update: {},
...options
}
Expand Down
3 changes: 2 additions & 1 deletion src/axios/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Deferred } from 'src/util/deferred';
import { KeyGenerator } from 'src/util/key-generator';
import { HeaderInterpreter } from '../header';
import { CachedResponse, CacheStorage } from '../storage/types';
import { CachePredicate } from '../util/cache-predicate';

export type DefaultCacheRequestConfig = AxiosRequestConfig & {
cache: CacheProperties;
Expand Down Expand Up @@ -43,7 +44,7 @@ export type CacheProperties = {
*
* @default ({ status }) => status >= 200 && status < 300
*/
shouldCache: (response: AxiosResponse) => boolean;
cachePredicate: CachePredicate;

/**
* Once the request is resolved, this specifies what requests should we change the cache.
Expand Down
13 changes: 10 additions & 3 deletions src/interceptors/response.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AxiosCacheInstance } from '../axios/types';
import { updateCache } from '../util/update-cache';
import {checkPredicateObject} from '../util/cache-predicate'

export function applyResponseInterceptor(axios: AxiosCacheInstance): void {
axios.interceptors.response.use(async (response) => {
Expand All @@ -8,11 +9,17 @@ export function applyResponseInterceptor(axios: AxiosCacheInstance): void {
updateCache(axios, response.data, response.config.cache.update);
}

const shouldCache = response.config.cache?.shouldCache || axios.defaults.cache.shouldCache;
const cachePredicate = response.config.cache?.cachePredicate || axios.defaults.cache.cachePredicate;

// Config told that this response should be cached.
if (shouldCache(response)) {
return response;
if (typeof cachePredicate === 'function') {
if(!cachePredicate(response)) {
return response;
}
} else {
if(!checkPredicateObject(response, cachePredicate)) {
return response;
}
}

const key = axios.generateKey(response.config);
Expand Down
63 changes: 63 additions & 0 deletions src/util/cache-predicate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { AxiosResponse } from 'axios';

export type CachePredicate = CachePredicateObject | ((response: AxiosResponse) => boolean);

export type CachePredicateObject = {
/**
* The status predicate, if a tuple is returned,
* the first and seconds value means the interval (inclusive) accepted.
* Can also be a function.
*/
statusCheck?: [start: number, end: number] | ((status: number) => boolean);

/**
* Matches if the response header container all keys. A tuple also checks for values.
*/
containsHeaders?: (string | [string, string])[];

/**
* Check if the desired response matches this predicate.
*/
responseMatch?: (res: any | undefined) => boolean;
};

export function checkPredicateObject(
response: AxiosResponse,
{ statusCheck, containsHeaders: containsHeader, responseMatch }: CachePredicateObject
): boolean {
if (statusCheck) {
if (typeof statusCheck === 'function') {
if (!statusCheck(response.status)) {
return false;
}
} else {
const [start, end] = statusCheck;
if (response.status <= start || response.status >= end) {
return false;
}
}
}

if (containsHeader) {
for (const entry of containsHeader) {
if (typeof entry === 'string') {
if (!response.headers[entry]) {
return false;
}
} else {
const [key, value] = entry;
if (!response.headers[key] || response.headers[key] == value) {
return false;
}
}
}
}

if (responseMatch) {
if (!responseMatch(response.data)) {
return false;
}
}

return true;
}

0 comments on commit 892dab4

Please sign in to comment.