Skip to content

Commit eac59aa

Browse files
authored
Adds a custom adapter (#5)
Fixes #1 and #2 - Adds `onSync` which receives the current request promise. - Removes the use of interceptor in favor of a custom (but similar) implementation of the interceptors in our new adaptor. It's now possible to return a promise in any of the middleware handler functions.
1 parent 1e568d9 commit eac59aa

File tree

17 files changed

+4588
-2183
lines changed

17 files changed

+4588
-2183
lines changed

.eslintrc.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
22

33
module.exports = {
44
root: true,
5-
6-
parserOptions: {
7-
parser: 'babel-eslint',
8-
sourceType: 'module',
9-
},
105
env: {
116
browser: true,
127
},

.travis.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,12 @@ node_js:
33
- node
44
notifications:
55
email: false
6+
before_install:
7+
- npm i -g [email protected]
8+
install:
9+
- npm ci
610
before_script:
711
- npm run build:dev
12+
cache:
13+
directories:
14+
- "$HOME/.npm"

README.md

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,49 +16,33 @@ npm install --save axios-middleware
1616

1717
## How to use
1818

19-
### Create your middleware
20-
21-
Here's a simple example of a locale middleware who sets a language header on each AJAX request.
22-
23-
```javascript
24-
import { HttpMiddleware } from 'axios-middleware';
25-
26-
export default class LocaleMiddleware extends HttpMiddleware {
27-
constructor(i18n) {
28-
super();
29-
this.i18n = i18n;
30-
}
31-
32-
onRequest(config) {
33-
config.headers = {
34-
locale: this.i18n.lang,
35-
...config.headers
36-
};
37-
return config;
38-
}
39-
}
40-
```
41-
42-
### Use the middleware service
43-
44-
Simplest use-case:
19+
A simple example using the [simplified middleware syntax](https://emileber.github.io/axios-middleware/#/simplified-syntax).
4520

4621
```javascript
4722
import axios from 'axios';
4823
import { HttpMiddlewareService } from 'axios-middleware';
49-
import i18n from './i18n';
50-
import { LocaleMiddleware, OtherMiddleware } from './middlewares';
5124

5225
// Create a new service instance
5326
const service = new HttpMiddlewareService(axios);
5427

5528
// Then register your middleware instances.
56-
service.register([
57-
new LocaleMiddleware(i18n),
58-
new OtherMiddleware()
59-
]);
29+
service.register({
30+
onRequest(config) {
31+
// handle the request config
32+
return config;
33+
},
34+
onSync(promise) {
35+
// handle the promsie
36+
return promise;
37+
},
38+
onResponse(response) {
39+
// handle the response
40+
return response;
41+
}
42+
});
6043

6144
// We're good to go!
45+
export default { service };
6246
```
6347

6448
A common use-case would be to expose an instance of the service which consumes an _axios_ instance configured for an API. It's then possible to register middlewares for this API at different stages of the initialization process of an application.

build/configs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const version = process.env.VERSION || pkg.version;
77
const name = 'axios-middleware';
88
const banner =
99
`/**
10-
* axios-middleware v${version}
10+
* ${name} v${version}
1111
* (c) ${new Date().getFullYear()} Émile Bergeron
1212
* @license MIT
1313
*/`;

docs/README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ Simple [axios](https://github.com/axios/axios) HTTP middleware service to simpli
66

77
There are two classes exposed in this module:
88

9-
- `HttpMiddleware`: the base class to extend from when creating your own middleware.
10-
- `HttpMiddlewareService` which manages the middleware stack and the hooking into the passed axios.
9+
- [`HttpMiddleware`](api/HttpMiddleware.md): the base class to extend from when creating your own middleware.
10+
- [`HttpMiddlewareService`](api/HttpMiddlewareService.md) which manages the middleware stack and the hooking into the passed axios.
1111

1212
It works with either the global axios or a local instance.
1313

@@ -30,11 +30,17 @@ const service = new HttpMiddlewareService(axios);
3030

3131
// Then register your middleware instances.
3232
service.register({
33-
onRequest() {
34-
// handle the request
33+
onRequest(config) {
34+
// handle the request config
35+
return config;
3536
},
36-
onResponseError(error) {
37-
// handle the response error
37+
onSync(promise) {
38+
// handle the promsie
39+
return promise;
40+
},
41+
onResponse(response) {
42+
// handle the response
43+
return response;
3844
}
3945
});
4046

docs/_sidebar.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- Examples
1111
- [Locale middleware](examples/locale-middleware.md)
1212
- [Service module](examples/service.md)
13+
- [Returning promises](examples/promise.md)
1314
- [ES5 usage](examples/es5.md)
1415
- [Browser usage](examples/browser.md)
1516

docs/api/HttpMiddleware.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,20 @@ The constructor isn't used in the default middleware, leaving it totally availab
1212

1313
Receives the configuration objects before the request is made. Useful to add headers, query parameters, validate data, etc.
1414

15-
!> It must return the received `config` even if no changes were made to it.
15+
!> It must return the received `config` even if no changes were made to it. It can also return a promise that should resolve with the config to use for the request.
1616

1717
## `onRequestError(error)`
1818

1919
No internet connection right now? You might end up in this function. Do what you need with the error.
2020

21+
You can return a promise, or throw another error to keep the middleware chain going.
22+
23+
## `onSync(promise)`
24+
25+
The request is being made and its promise is being passed. Do what you want with it but be sure to **return a promise**, be it the one just received or a new one.
26+
27+
?> Useful to implement a sort of loading indication based on all the unresolved requests being made.
28+
2129
## `onResponse(response)`
2230

2331
Parsing the response can be done here. Say all responses from your API are returned nested within a `_data` property?
@@ -28,8 +36,10 @@ onResponse(response) {
2836
}
2937
```
3038

31-
!> The original `response` object or _a new one_ should be returned.
39+
!> The original `response` object, _a new one_, or a promise should be returned.
3240

3341
## `onResponseError(error)`
3442

3543
Not authenticated? Server problems? You might end up here. Do what you need with the error.
44+
45+
?> You can return a promise, which is useful when you want to retry failed requests.

docs/api/HttpMiddlewareService.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# HttpMiddlewareService
22

3-
This is the heart of this plugin module. It works by leveraging axios interceptors to call its middleware queue.
3+
This is the heart of this plugin module. It works by leveraging axios' adapter to call its middleware stack at each relevant steps of a request.
44

55
## `constructor(axios)`
66

@@ -16,22 +16,29 @@ Sets or replaces the axios instance on which to intercept the requests and respo
1616

1717
Removes the registered interceptors on the axios instance, if any were set.
1818

19+
!> Be aware that changing the default adapter after the middleware service was initialized, then calling `unsetHttp` or `setHttp` will set the default adapter back in the axios instance. Any adapter used after could be lost.
20+
1921
## `has(middleware)`
2022

21-
Returns `true` is the passed `middleware` instance is within the queue.
23+
Returns `true` if the passed `middleware` instance is within the stack.
2224

2325
## `register(middlewares)`
2426

25-
Adds a middleware instance or an array of middlewares to the queue.
27+
Adds a middleware instance or an array of middlewares to the stack.
2628

2729
You can pass an `HttpMiddleware` instance or a simple object implementing only the functions you need (see the [simplified syntax](simplified-syntax.md)).
2830

29-
!> Throws an error if a middleware instance is already within the queue.
31+
!> Throws an error if a middleware instance is already within the stack.
3032

3133
## `unregister(middleware)`
3234

33-
Removes a middleware instance from the queue.
35+
Removes a middleware instance from the stack.
3436

3537
## `reset()`
3638

37-
Empty the middleware queue.
39+
Empty the middleware stack.
40+
41+
## `adapter(config)`
42+
43+
The adapter function that replaces the default axios adapter. It calls the default implementation and passes the resulting promise to the middleware stack's `onSync` method.
44+

docs/examples/promise.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Returning promises
2+
3+
In a case where we'd like to retry a request if not authenticated, we could return a promise in the `onResponseError` method.
4+
5+
```javascript
6+
import { HttpMiddleware } from 'axios-middleware';
7+
8+
export default class AuthMiddleware extends HttpMiddleware {
9+
constructor(auth, http) {
10+
super();
11+
this.auth = auth;
12+
this.http = http;
13+
}
14+
15+
onResponseError(err) {
16+
if (err.response.status === 401 && err.config && !err.config.hasRetriedRequest) {
17+
return this.auth()
18+
.then(function (token) {
19+
err.config.hasRetriedRequest = true;
20+
err.config.headers.Authorization = `Bearer ${token}`;
21+
22+
// Retrying the request now that we're authenticated.
23+
return this.http(err.config);
24+
})
25+
.catch(function (error) {
26+
console.log('Refresh login error: ', error);
27+
throw error;
28+
});
29+
}
30+
throw err;
31+
}
32+
}
33+
```

docs/simplified-syntax.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Simplified syntax for middlewares
22

3-
Instead of creating a base class from the [`HttpMiddleware`](api/HttpMiddleware.md) base class, you can use a simple object literal only implementing the functions you need.
3+
Instead of creating a class from the [`HttpMiddleware`](api/HttpMiddleware.md) base class, you can use a simple object literal only implementing the functions you need.
44

55
```javascript
66
service.register({

0 commit comments

Comments
 (0)