Skip to content

Commit

Permalink
V3.0.0 (#111)
Browse files Browse the repository at this point in the history
v3.0.0:
 - deprecated `skipWhileRefresh`
 - renamed `skipWhileRefresh` flag to `pauseInstanceWhileRefreshing`
 - changed default behavior of `pauseInstanceWhileRefreshing`
  • Loading branch information
Flyrell authored Aug 28, 2020
1 parent 92bdabb commit 751c212
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 25 deletions.
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ In order to activate the interceptors, you need to import a function from `axios
which is *exported by default* and call it with the **axios instance** you want the interceptors for,
as well as the **refresh authorization function** where you need to write the logic for refreshing the authorization.

The interceptors will then be bound onto the axios instance and the specified logic will be run whenever a [401 (Unauthorized)](https://httpstatuses.com/401) status code
The interceptors will then be bound onto the axios instance, and the specified logic will be run whenever a [401 (Unauthorized)](https://httpstatuses.com/401) status code
is returned from a server (or any other status code you provide in options). All the new requests created while the refreshAuthLogic has been processing will be bound onto the
Promise returned from the refreshAuthLogic function. This means that the requests will be resolved when a new access token has been fetched or when the refreshing logic faleid.

Expand Down Expand Up @@ -144,17 +144,22 @@ stalled request is called with the request configuration object.
}
```

#### Unpause the instance while refreshing
#### Pause the instance while "refresh logic" is running

While your refresh logic is ran, the instance is marked as "to-be-skipped"
in order to prevent the "interceptors loop" when refreshing causes one of the statuses specified
in `options.statusCodes`. If that's behavior is not wanted, you can set the `skipWhileRefreshing` option to false,
but keep in mind that you need to implement skipping the requests by yourself using `skipAuthRefresh` flag
in request's configuration
While your refresh logic is running, the interceptor will be triggered for every request
which returns one of the `options.statusCodes` specified (HTTP 401 by default).

In order to prevent the interceptors loop (when your refresh logic fails with any of the status
codes specified in `options.statusCodes`) you need to use a [`skipAuthRefresh`](#skipping-the-interceptor)
flag on your refreshing call inside the `refreshAuthLogic` function.

In case your refresh logic does not make any calls, you should consider using the following flag
when initializing the interceptor to pause the whole axios instance while the refreshing is pending.
This prevents interceptor from running for each failed request.

```javascript
{
skipWhileRefreshing: false // default: true
pauseInstanceWhileRefreshing: true // default: false
}
```

Expand All @@ -168,6 +173,14 @@ have you used it for something else? Create a PR with your use case to share it.

---

### Changelog

- **v3.0.0**
- `skipWhileRefresh` flag has been deprecated due to its unclear name and its logic has been moved to `pauseInstanceWhileRefreshing` flag
- `pauseInstanceWhileRefreshing` is set to `false` by default

---

#### Want to help?
Check out [contribution guide](CONTRIBUTING.md) or my [patreon page!](https://www.patreon.com/dawidzbinski)

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "axios-auth-refresh",
"version": "2.2.8",
"version": "3.0.0",
"description": "Axios plugin which makes it very easy to automatically refresh the authorization tokens of your clients",
"keywords": [
"axios",
Expand Down
28 changes: 24 additions & 4 deletions src/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,6 @@ describe('Merges configs', () => {
});
});

describe('Uses options correctly', () => {

});

describe('Determines if the response should be intercepted', () => {

let cache: AxiosAuthRefreshCache = undefined;
Expand Down Expand Up @@ -133,6 +129,30 @@ describe('Determines if the response should be intercepted', () => {
};
expect(shouldInterceptError(error, options, axios, cache)).toBeTruthy();
});

it('when pauseInstanceWhileRefreshing flag is not provided', () => {
const error = {
response: { status: 401 },
};
expect(shouldInterceptError(error, options, axios, cache)).toBeTruthy();
});

it('when pauseInstanceWhileRefreshing flag is set to true', () => {
const error = {
response: { status: 401 },
};
const newCache = { ...cache, skipInstances: [ axios ] };
const newOptions = { ...options, pauseInstanceWhileRefreshing: true };
expect(shouldInterceptError(error, newOptions, axios, newCache)).toBeFalsy();
});

it('when pauseInstanceWhileRefreshing flag is set to false', () => {
const error = {
response: { status: 401 },
};
const newOptions = { ...options, pauseInstanceWhileRefreshing: false };
expect(shouldInterceptError(error, newOptions, axios, cache)).toBeTruthy();
});
});

describe('Creates refresh call', () => {
Expand Down
12 changes: 10 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ import {
shouldInterceptError,
AxiosAuthRefreshCache,
createRequestQueueInterceptor,
} from "./utils";
} from './utils';

export interface AxiosAuthRefreshOptions {
statusCodes?: Array<number>;
retryInstance?: AxiosInstance;
/**
* @deprecated
* This flag has been deprecated in favor of `pauseInstanceWhileRefreshing` flag.
* Use `pauseInstanceWhileRefreshing` instead.
*/
skipWhileRefreshing?: boolean;
pauseInstanceWhileRefreshing?: boolean;
onRetry?: (requestConfig: AxiosRequestConfig) => AxiosRequestConfig
}

Expand Down Expand Up @@ -60,7 +66,9 @@ export default function createAuthRefreshInterceptor(
return Promise.reject(error);
}

cache.skipInstances.push(instance);
if (options.pauseInstanceWhileRefreshing) {
cache.skipInstances.push(instance);
}

// If refresh call does not exist, create one
const refreshing = createRefreshCall(error, refreshAuthCall, cache);
Expand Down
22 changes: 13 additions & 9 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AxiosAuthRefreshOptions } from "./index";
import axios, { AxiosInstance, AxiosPromise } from "axios";
import { AxiosAuthRefreshOptions } from './index';
import axios, { AxiosInstance, AxiosPromise } from 'axios';

export interface AxiosAuthRefreshCache {
skipInstances: AxiosInstance[];
Expand All @@ -9,19 +9,23 @@ export interface AxiosAuthRefreshCache {

export const defaultOptions: AxiosAuthRefreshOptions = {
statusCodes: [ 401 ],
skipWhileRefreshing: true,
pauseInstanceWhileRefreshing: false,
};

/**
* Merges two options objects (source rewrites target).
* Merges two options objects (options overwrites defaults).
*
* @return {AxiosAuthRefreshOptions}
*/
export function mergeOptions(
target: AxiosAuthRefreshOptions,
source: AxiosAuthRefreshOptions,
defaults: AxiosAuthRefreshOptions,
options: AxiosAuthRefreshOptions,
): AxiosAuthRefreshOptions {
return { ...target, ...source };
return {
...defaults,
pauseInstanceWhileRefreshing: options.skipWhileRefreshing,
...options,
};
}

/**
Expand All @@ -40,15 +44,15 @@ export function shouldInterceptError(
return false;
}

if (error.config && error.config.skipAuthRefresh) {
if (error.config?.skipAuthRefresh) {
return false;
}

if (!error.response || !options.statusCodes.includes(parseInt(error.response.status))) {
return false;
}

return !options.skipWhileRefreshing || !cache.skipInstances.includes(instance);
return !options.pauseInstanceWhileRefreshing || !cache.skipInstances.includes(instance);
}

/**
Expand Down

0 comments on commit 751c212

Please sign in to comment.