Skip to content

Commit 0cf17e2

Browse files
committed
Merge pull request #16 from chimurai/shorthand
Shorthand support
2 parents bb473ad + 3da46aa commit 0cf17e2

File tree

6 files changed

+217
-22
lines changed

6 files changed

+217
-22
lines changed

README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ var proxy = proxyMiddleware('/api', {target: 'http://www.example.org'});
2121
// | |
2222
// context options
2323

24-
// 'proxy' is now ready to be used in a server.
24+
// 'proxy' is now ready to be used in a server.
25+
26+
// shorthand syntax for the example above:
27+
// proxyMiddleware('http://www.example.org/api');
2528

2629
```
2730
* **context**: matches provided context against request-urls' path.
@@ -39,8 +42,10 @@ A simple example with express server.
3942
var express = require('express');
4043
var proxyMiddleware = require('http-proxy-middleware');
4144

42-
// configure proxy middleware
45+
// configure proxy middleware context
4346
var context = '/api'; // requests with this path will be proxied
47+
48+
// configure proxy middleware options
4449
var options = {
4550
target: 'http://www.example.org', // target host
4651
changeOrigin: true, // needed for virtual hosted sites
@@ -64,7 +69,7 @@ var app = express();
6469
app.listen(3000);
6570
```
6671

67-
See [working examples](#more-examples).
72+
Check out [working examples](#more-examples).
6873

6974
**Tip:** For [name-based virtual hosted sites](http://en.wikipedia.org/wiki/Virtual_hosting#Name-based), you'll need to use the option `changeOrigin` and set it to `true`.
7075

@@ -91,6 +96,22 @@ Request URL's [ _path-absolute_ and _query_](https://tools.ietf.org/html/rfc3986
9196
* `['/api/**', '!**/bad.json']` exclusion
9297

9398

99+
### Shorthand
100+
Use the shorthand syntax for simple use cases. The `context` and `option.target` will be automatically configured when shorthand is used. Options can still be used if needed.
101+
102+
```javascript
103+
proxyMiddleware('http://www.example.org:8000/api');
104+
// proxyMiddleware('/api', {target: 'http://www.example.org:8000'});
105+
106+
107+
proxyMiddleware('http://www.example.org:8000/api/books/*/**.json');
108+
// proxyMiddleware('/api/books/*/**.json', {target: 'http://www.example.org:8000'});
109+
110+
111+
proxyMiddleware('http://www.example.org:8000/api', {changeOrigin:true});
112+
// proxyMiddleware('/api', {target: 'http://www.example.org:8000', changeOrigin: true});
113+
```
114+
94115
### Options
95116
* **option.pathRewrite**: object, rewrite target's url path. Object-keys will be used as _RegExp_ to match paths.
96117
```javascript
@@ -194,7 +215,7 @@ $ npm test
194215
$ npm run cover
195216
```
196217
197-
### Changlog
218+
### Changelog
198219
* [v0.6.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.6.0) - support proxyTable
199220
* [v0.5.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.5.0) - support subscribing to http-proxy error- and proxyRes-event
200221
* [v0.4.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.4.0) - support websocket

index.js

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,19 @@
11
var _ = require('lodash');
22
var httpProxy = require('http-proxy');
3+
var configFactory = require('./lib/config-factory');
34
var handlers = require('./lib/handlers');
45
var contextMatcher = require('./lib/context-matcher');
56
var PathRewriter = require('./lib/path-rewriter');
67
var ProxyTable = require('./lib/proxy-table');
78

89
var httpProxyMiddleware = function (context, opts) {
910
var isWsUpgradeListened = false;
10-
var proxyOptions = opts || {};
11-
12-
// Legacy option.proxyHost
13-
// set options.headers.host when option.proxyHost is provided
14-
if (proxyOptions.proxyHost) {
15-
console.log('*************************************');
16-
console.log('[HPM] Deprecated "option.proxyHost"');
17-
console.log(' Use "option.changeOrigin" or "option.headers.host" instead');
18-
console.log(' "option.proxyHost" will be removed in future release.');
19-
console.log('*************************************');
20-
21-
proxyOptions.headers = proxyOptions.headers || {};
22-
proxyOptions.headers.host = proxyOptions.proxyHost;
23-
}
11+
var config = configFactory.createConfig(context, opts);
12+
var proxyOptions = config.options;
2413

2514
// create proxy
2615
var proxy = httpProxy.createProxyServer(proxyOptions);
27-
console.log('[HPM] Proxy created:', context, ' -> ', proxyOptions.target);
16+
console.log('[HPM] Proxy created:', config.context, ' -> ', proxyOptions.target);
2817

2918
var pathRewriter = PathRewriter.create(proxyOptions.pathRewrite); // returns undefined when "pathRewrite" is not provided
3019

@@ -56,7 +45,7 @@ var httpProxyMiddleware = function (context, opts) {
5645
return middleware;
5746

5847
function middleware (req, res, next) {
59-
if (contextMatcher.match(context, req.url)) {
48+
if (contextMatcher.match(config.context, req.url)) {
6049
if (proxyOptions.proxyTable) {
6150
// change option.target when proxyTable present.
6251
proxy.web(req, res, ProxyTable.createProxyOptions(req, proxyOptions));
@@ -82,7 +71,7 @@ var httpProxyMiddleware = function (context, opts) {
8271
isWsUpgradeListened = true;
8372

8473
req.connection.server.on('upgrade', function (req, socket, head) {
85-
if (contextMatcher.match(context, req.url)) {
74+
if (contextMatcher.match(config.context, req.url)) {
8675
if (pathRewriter) {
8776
req.url = pathRewriter(req.url);
8877
}

lib/config-factory.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
var _ = require('lodash');
2+
var url = require('url');
3+
4+
module.exports = {
5+
createConfig : createConfig
6+
};
7+
8+
function createConfig (context, opts) {
9+
// structure of config object to be returned
10+
var config = {
11+
context : undefined,
12+
options : {}
13+
};
14+
15+
var useShortHand = isShortHand(context);
16+
17+
if (useShortHand) {
18+
var oUrl = url.parse(context);
19+
var target = [oUrl.protocol, '//', oUrl.host].join('');
20+
21+
config.context = oUrl.pathname;
22+
config.options = _.assign(config.options, {target:target}, opts);
23+
} else {
24+
config.context = context;
25+
config.options = _.assign(config.options, opts);
26+
}
27+
28+
// Legacy option.proxyHost
29+
config.options = mapLegacyProxyHostOption(config.options);
30+
31+
if (!config.options.target) {
32+
throw new Error('[HPM] Missing "target" option. Example: {target: "http://www.example.org"}');
33+
}
34+
35+
return config;
36+
};
37+
38+
function isShortHand (context) {
39+
if (_.isString(context)) {
40+
return (url.parse(context).host) ? true : false;
41+
}
42+
}
43+
44+
function mapLegacyProxyHostOption (options) {
45+
// set options.headers.host when option.proxyHost is provided
46+
if (options.proxyHost) {
47+
console.log('*************************************');
48+
console.log('[HPM] Deprecated "option.proxyHost"');
49+
console.log(' Use "option.changeOrigin" or "option.headers.host" instead');
50+
console.log(' "option.proxyHost" will be removed in future release.');
51+
console.log('*************************************');
52+
53+
options.headers = options.headers || {};
54+
options.headers.host = options.proxyHost;
55+
}
56+
57+
return options;
58+
}

lib/handlers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module.exports = {
2-
proxyError : proxyError
2+
proxyError : proxyError
33
}
44

55
function proxyError (err, req, res) {

test/config-factory.spec.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
var expect = require('chai').expect;
2+
var configFactory = require('../lib/config-factory');
3+
4+
describe('configFactory', function () {
5+
var result;
6+
7+
describe('createConfig()', function () {
8+
9+
describe('classic api', function () {
10+
var context = '/api';
11+
var options = {target: 'http://www.example.org'};
12+
13+
beforeEach(function () {
14+
result = configFactory.createConfig(context, options);
15+
});
16+
17+
it('should return on config object', function () {
18+
expect(result).to.have.all.keys('context', 'options');
19+
});
20+
21+
it('should return on config object with context', function () {
22+
expect(result.context).to.equal(context);
23+
});
24+
25+
it('should return on config object with options', function () {
26+
expect(result.options).to.deep.equal(options);
27+
});
28+
});
29+
30+
describe('shorthand api', function () {
31+
beforeEach(function () {
32+
result = configFactory.createConfig('http://www.example.org:8000/api');
33+
});
34+
35+
it('should return on config object', function () {
36+
expect(result).to.have.all.keys('context', 'options');
37+
});
38+
39+
it('should return on config object with context', function () {
40+
expect(result.context).to.equal('/api');
41+
});
42+
43+
it('should return on config object with options', function () {
44+
expect(result.options).to.deep.equal({target: 'http://www.example.org:8000'});
45+
});
46+
});
47+
48+
describe('shorthand api for whole domain', function () {
49+
beforeEach(function () {
50+
result = configFactory.createConfig('http://www.example.org:8000');
51+
});
52+
53+
it('should return on config object with context', function () {
54+
expect(result.context).to.equal('/');
55+
});
56+
});
57+
58+
describe('shorthand api with globbing', function () {
59+
beforeEach(function () {
60+
result = configFactory.createConfig('http://www.example.org:8000/api/*.json');
61+
});
62+
63+
it('should return on config object with context', function () {
64+
expect(result.context).to.equal('/api/*.json');
65+
});
66+
});
67+
68+
describe('shorthand api with options', function () {
69+
beforeEach(function () {
70+
result = configFactory.createConfig('http://www.example.org:8000/api', {changeOrigin: true});
71+
});
72+
73+
it('should return on config object with additional options', function () {
74+
expect(result.options).to.deep.equal({target: 'http://www.example.org:8000', changeOrigin: true});
75+
});
76+
});
77+
78+
describe('missing option.target', function () {
79+
var fn
80+
beforeEach(function () {
81+
fn = function () {
82+
configFactory.createConfig('/api');
83+
}
84+
});
85+
86+
it('should throw an error when target option is missing', function () {
87+
expect(fn).to.throw(Error);
88+
});
89+
});
90+
91+
92+
});
93+
94+
});
95+

test/http-proxy-middleware.spec.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,38 @@ describe('http-proxy-middleware in actual server', function () {
462462
});
463463
});
464464

465+
describe('shorthand usage', function () {
466+
var proxyServer, targetServer;
467+
var responseBody;
468+
469+
beforeEach(function (done) {
470+
var mw_proxy = proxyMiddleware('http://localhost:8000/api');
471+
var mw_target = function (req, res, next) {
472+
res.write(req.url); // respond with req.url
473+
res.end();
474+
};
475+
476+
proxyServer = createServer(3000, mw_proxy);
477+
targetServer = createServer(8000, mw_target);
478+
479+
http.get('http://localhost:3000/api/foo/bar', function (res) {
480+
res.on('data', function (chunk) {
481+
responseBody = chunk.toString();
482+
done();
483+
});
484+
});
485+
});
486+
487+
afterEach(function () {
488+
proxyServer.close();
489+
targetServer.close();
490+
});
491+
492+
it('should have proxy with shorthand configuration', function () {
493+
expect(responseBody).to.equal('/api/foo/bar');
494+
});
495+
});
496+
465497

466498
});
467499

0 commit comments

Comments
 (0)