Skip to content

Commit 7341704

Browse files
committed
feat(plugins): add support for plugins
1 parent b674a71 commit 7341704

File tree

4 files changed

+73
-0
lines changed

4 files changed

+73
-0
lines changed

README.md

+17
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option
7272
- [`pathFilter` (string, []string, glob, []glob, function)](#pathfilter-string-string-glob-glob-function)
7373
- [`pathRewrite` (object/function)](#pathrewrite-objectfunction)
7474
- [`router` (object/function)](#router-objectfunction)
75+
- [`plugins` (Array)](#plugins-array)
7576
- [`logLevel` (string)](#loglevel-string)
7677
- [`logProvider` (function)](#logprovider-function)
7778
- [`http-proxy` events](#http-proxy-events)
@@ -270,6 +271,22 @@ router: async function(req) {
270271
}
271272
```
272273

274+
### `plugins` (Array)
275+
276+
```js
277+
const simpleRequestLogger = (proxy, options) => {
278+
proxy.on('proxyReq', (proxyReq, req, res) => {
279+
console.log(`[HPM] [${req.method}] ${req.url}`); // outputs: [HPM] GET /users
280+
});
281+
},
282+
283+
const config = {
284+
target: `http://example.org`,
285+
changeOrigin: true,
286+
plugins: [simpleRequestLogger],
287+
};
288+
```
289+
273290
### `logLevel` (string)
274291

275292
Default: `'info'`

src/http-proxy-middleware.ts

+7
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export class HttpProxyMiddleware {
2525
this.proxy = httpProxy.createProxyServer({});
2626
this.logger.info(`[HPM] Proxy created: ${options.pathFilter ?? '/'} -> ${options.target}`);
2727

28+
this.registerPlugins(this.proxy, this.proxyOptions);
29+
2830
this.pathRewriter = PathRewriter.createPathRewriter(this.proxyOptions.pathRewrite); // returns undefined when "pathRewrite" is not provided
2931

3032
// attach handler to http-proxy events
@@ -79,6 +81,11 @@ export class HttpProxyMiddleware {
7981
}
8082
};
8183

84+
private registerPlugins(proxy: httpProxy, options: Options) {
85+
const plugins = options.plugins ?? [];
86+
plugins.forEach((plugin) => plugin(proxy, options));
87+
}
88+
8289
private catchUpgradeRequest = (server: https.Server) => {
8390
if (!this.wsInternalSubscribed) {
8491
server.on('upgrade', this.handleUpgrade);

src/types.ts

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export interface RequestHandler {
2121

2222
export type Filter = string | string[] | ((pathname: string, req: Request) => boolean);
2323

24+
export type Plugin = (proxy: httpProxy, options: Options) => void;
25+
2426
export interface Options extends httpProxy.ServerOptions {
2527
/**
2628
* Narrow down requests to proxy or not.
@@ -32,6 +34,10 @@ export interface Options extends httpProxy.ServerOptions {
3234
| { [regexp: string]: string }
3335
| ((path: string, req: Request) => string)
3436
| ((path: string, req: Request) => Promise<string>);
37+
/**
38+
* Plugins have access to the internal http-proxy instance to customize behavior.
39+
*/
40+
plugins?: Plugin[];
3541
router?:
3642
| { [hostOrPath: string]: httpProxy.ServerOptions['target'] }
3743
| ((req: Request) => httpProxy.ServerOptions['target'])

test/e2e/plugins.spec.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { createProxyMiddleware, createApp } from './test-kit';
2+
import * as request from 'supertest';
3+
import { getLocal, Mockttp } from 'mockttp';
4+
import type { Options, Plugin } from '../../src/types';
5+
6+
describe('E2E Plugins', () => {
7+
let mockTargetServer: Mockttp;
8+
9+
beforeEach(async () => {
10+
mockTargetServer = getLocal();
11+
await mockTargetServer.start();
12+
});
13+
14+
afterEach(async () => {
15+
await mockTargetServer.stop();
16+
});
17+
18+
it('should register a plugin and access the http-proxy object', async () => {
19+
let proxyReqUrl: string;
20+
let responseStatusCode: number;
21+
22+
mockTargetServer.forGet('/users/1').thenReply(200, '{"userName":"John"}');
23+
24+
const simplePlugin: Plugin = (proxy) => {
25+
proxy.on('proxyReq', (proxyReq, req, res, options) => (proxyReqUrl = req.url));
26+
proxy.on('proxyRes', (proxyRes, req, res) => (responseStatusCode = proxyRes.statusCode));
27+
};
28+
29+
const config: Options = {
30+
target: `http://localhost:${mockTargetServer.port}`,
31+
plugins: [simplePlugin], // register a plugin
32+
};
33+
const proxyMiddleware = createProxyMiddleware(config);
34+
const app = createApp(proxyMiddleware);
35+
const agent = request(app);
36+
37+
const response = await agent.get('/users/1').expect(200);
38+
39+
expect(proxyReqUrl).toBe('/users/1');
40+
expect(response.text).toBe('{"userName":"John"}');
41+
expect(responseStatusCode).toBe(200);
42+
});
43+
});

0 commit comments

Comments
 (0)