Skip to content

Commit 2621cd3

Browse files
LiranBrichimurai
authored andcommitted
feat: async router (#379)
* feat: async router * fix: lint * fix: tests to expect promise from GetTarget * tests: async function * doc: README example
1 parent 3b97308 commit 2621cd3

File tree

4 files changed

+52
-20
lines changed

4 files changed

+52
-20
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@ Providing an alternative way to decide which requests should be proxied; In case
217217
router: function(req) {
218218
return 'http://localhost:8004';
219219
}
220+
221+
// Asynchronous router function which returns promise
222+
router: async function(req) {
223+
const url = await doSomeIO();
224+
return url;
225+
}
220226
```
221227

222228
- **option.logLevel**: string, ['debug', 'info', 'warn', 'error', 'silent']. Default: `'info'`

src/http-proxy-middleware.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class HttpProxyMiddleware {
4747
// https://github.com/Microsoft/TypeScript/wiki/'this'-in-TypeScript#red-flags-for-this
4848
public middleware = async (req, res, next) => {
4949
if (this.shouldProxy(this.config.context, req)) {
50-
const activeProxyOptions = this.prepareProxyRequest(req);
50+
const activeProxyOptions = await this.prepareProxyRequest(req);
5151
this.proxy.web(req, res, activeProxyOptions);
5252
} else {
5353
next();
@@ -68,9 +68,9 @@ export class HttpProxyMiddleware {
6868
}
6969
};
7070

71-
private handleUpgrade = (req, socket, head) => {
71+
private handleUpgrade = async (req, socket, head) => {
7272
if (this.shouldProxy(this.config.context, req)) {
73-
const activeProxyOptions = this.prepareProxyRequest(req);
73+
const activeProxyOptions = await this.prepareProxyRequest(req);
7474
this.proxy.ws(req, socket, head, activeProxyOptions);
7575
this.logger.info('[HPM] Upgrading to WebSocket');
7676
}
@@ -97,7 +97,7 @@ export class HttpProxyMiddleware {
9797
* @param {Object} req
9898
* @return {Object} proxy options
9999
*/
100-
private prepareProxyRequest = req => {
100+
private prepareProxyRequest = async req => {
101101
// https://github.com/chimurai/http-proxy-middleware/issues/17
102102
// https://github.com/chimurai/http-proxy-middleware/issues/94
103103
req.url = req.originalUrl || req.url;
@@ -109,7 +109,7 @@ export class HttpProxyMiddleware {
109109
// Apply in order:
110110
// 1. option.router
111111
// 2. option.pathRewrite
112-
this.applyRouter(req, newProxyOptions);
112+
await this.applyRouter(req, newProxyOptions);
113113
this.applyPathRewrite(req, this.pathRewriter);
114114

115115
// debug logging for both http(s) and websockets
@@ -133,11 +133,11 @@ export class HttpProxyMiddleware {
133133
};
134134

135135
// Modify option.target when router present.
136-
private applyRouter = (req, options) => {
136+
private applyRouter = async (req, options) => {
137137
let newTarget;
138138

139139
if (options.router) {
140-
newTarget = Router.getTarget(req, options);
140+
newTarget = await Router.getTarget(req, options);
141141

142142
if (newTarget) {
143143
this.logger.debug(

src/router.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import * as _ from 'lodash';
22
import { getInstance } from './logger';
33
const logger = getInstance();
44

5-
export function getTarget(req, config) {
5+
export async function getTarget(req, config) {
66
let newTarget;
77
const router = config.router;
88

99
if (_.isPlainObject(router)) {
1010
newTarget = getTargetFromProxyTable(req, router);
1111
} else if (_.isFunction(router)) {
12-
newTarget = router(req);
12+
newTarget = await router(req);
1313
}
1414

1515
return newTarget;

test/unit/router.spec.ts

+37-11
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,33 @@ describe('router unit test', () => {
4040
expect(request.url).toBe('/');
4141
});
4242
it('should return new target', () => {
43-
expect(result).toBe('http://foobar.com:666');
43+
expect(result).resolves.toBe('http://foobar.com:666');
44+
});
45+
});
46+
});
47+
48+
describe('router.getTarget from async function', () => {
49+
let request;
50+
51+
beforeEach(() => {
52+
proxyOptionWithRouter = {
53+
target: 'http://localhost:6000',
54+
async router(req) {
55+
request = req;
56+
return 'http://foobar.com:666';
57+
}
58+
};
59+
60+
result = getTarget(fakeReq, proxyOptionWithRouter);
61+
});
62+
63+
describe('custom dynamic router async function', () => {
64+
it('should provide the request object for dynamic routing', () => {
65+
expect(request.headers.host).toBe('localhost');
66+
expect(request.url).toBe('/');
67+
});
68+
it('should return new target', () => {
69+
expect(result).resolves.toBe('http://foobar.com:666');
4470
});
4571
});
4672
});
@@ -64,71 +90,71 @@ describe('router unit test', () => {
6490
describe('without router config', () => {
6591
it('should return the normal target when router not present in config', () => {
6692
result = getTarget(fakeReq, config);
67-
expect(result).toBeUndefined();
93+
expect(result).resolves.toBeUndefined();
6894
});
6995
});
7096

7197
describe('with just the host in router config', () => {
7298
it('should target http://localhost:6001 when for router:"alpha.localhost"', () => {
7399
fakeReq.headers.host = 'alpha.localhost';
74100
result = getTarget(fakeReq, proxyOptionWithRouter);
75-
expect(result).toBe('http://localhost:6001');
101+
expect(result).resolves.toBe('http://localhost:6001');
76102
});
77103

78104
it('should target http://localhost:6002 when for router:"beta.localhost"', () => {
79105
fakeReq.headers.host = 'beta.localhost';
80106
result = getTarget(fakeReq, proxyOptionWithRouter);
81-
expect(result).toBe('http://localhost:6002');
107+
expect(result).resolves.toBe('http://localhost:6002');
82108
});
83109
});
84110

85111
describe('with host and host + path config', () => {
86112
it('should target http://localhost:6004 without path', () => {
87113
fakeReq.headers.host = 'gamma.localhost';
88114
result = getTarget(fakeReq, proxyOptionWithRouter);
89-
expect(result).toBe('http://localhost:6004');
115+
expect(result).resolves.toBe('http://localhost:6004');
90116
});
91117

92118
it('should target http://localhost:6003 exact path match', () => {
93119
fakeReq.headers.host = 'gamma.localhost';
94120
fakeReq.url = '/api';
95121
result = getTarget(fakeReq, proxyOptionWithRouter);
96-
expect(result).toBe('http://localhost:6003');
122+
expect(result).resolves.toBe('http://localhost:6003');
97123
});
98124

99125
it('should target http://localhost:6004 when contains path', () => {
100126
fakeReq.headers.host = 'gamma.localhost';
101127
fakeReq.url = '/api/books/123';
102128
result = getTarget(fakeReq, proxyOptionWithRouter);
103-
expect(result).toBe('http://localhost:6003');
129+
expect(result).resolves.toBe('http://localhost:6003');
104130
});
105131
});
106132

107133
describe('with just the path', () => {
108134
it('should target http://localhost:6005 with just a path as router config', () => {
109135
fakeReq.url = '/rest';
110136
result = getTarget(fakeReq, proxyOptionWithRouter);
111-
expect(result).toBe('http://localhost:6005');
137+
expect(result).resolves.toBe('http://localhost:6005');
112138
});
113139

114140
it('should target http://localhost:6005 with just a path as router config', () => {
115141
fakeReq.url = '/rest/deep/path';
116142
result = getTarget(fakeReq, proxyOptionWithRouter);
117-
expect(result).toBe('http://localhost:6005');
143+
expect(result).resolves.toBe('http://localhost:6005');
118144
});
119145

120146
it('should target http://localhost:6000 path in not present in router config', () => {
121147
fakeReq.url = '/unknow-path';
122148
result = getTarget(fakeReq, proxyOptionWithRouter);
123-
expect(result).toBeUndefined();
149+
expect(result).resolves.toBeUndefined();
124150
});
125151
});
126152

127153
describe('matching order of router config', () => {
128154
it('should return first matching target when similar paths are configured', () => {
129155
fakeReq.url = '/some/specific/path';
130156
result = getTarget(fakeReq, proxyOptionWithRouter);
131-
expect(result).toBe('http://localhost:6006');
157+
expect(result).resolves.toBe('http://localhost:6006');
132158
});
133159
});
134160
});

0 commit comments

Comments
 (0)