Skip to content

Commit

Permalink
feat(plugins): add support for plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
chimurai committed Mar 21, 2022
1 parent b674a71 commit a8f7fde
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option
- [`pathFilter` (string, []string, glob, []glob, function)](#pathfilter-string-string-glob-glob-function)
- [`pathRewrite` (object/function)](#pathrewrite-objectfunction)
- [`router` (object/function)](#router-objectfunction)
- [`plugins` (Array)](#plugins-array)
- [`logLevel` (string)](#loglevel-string)
- [`logProvider` (function)](#logprovider-function)
- [`http-proxy` events](#http-proxy-events)
Expand Down Expand Up @@ -270,6 +271,22 @@ router: async function(req) {
}
```
### `plugins` (Array)
```js
const simpleRequestLogger = (proxy, options) => {
proxy.on('proxyReq', (proxyReq, req, res) => {
console.log(`[HPM] [${req.method}] ${req.url}`); // outputs: [HPM] GET /users
});
},

const config = {
target: `http://example.org`,
changeOrigin: true,
plugins: [simpleRequestLogger],
};
```
### `logLevel` (string)
Default: `'info'`
Expand Down
7 changes: 7 additions & 0 deletions src/http-proxy-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export class HttpProxyMiddleware {
this.proxy = httpProxy.createProxyServer({});
this.logger.info(`[HPM] Proxy created: ${options.pathFilter ?? '/'} -> ${options.target}`);

this.registerPlugins(this.proxy, this.proxyOptions);

this.pathRewriter = PathRewriter.createPathRewriter(this.proxyOptions.pathRewrite); // returns undefined when "pathRewrite" is not provided

// attach handler to http-proxy events
Expand Down Expand Up @@ -79,6 +81,11 @@ export class HttpProxyMiddleware {
}
};

private registerPlugins(proxy: httpProxy, options: Options) {
const plugins = options.plugins ?? [];
plugins.forEach((plugin) => plugin(proxy, options));
}

private catchUpgradeRequest = (server: https.Server) => {
if (!this.wsInternalSubscribed) {
server.on('upgrade', this.handleUpgrade);
Expand Down
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export interface RequestHandler {

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

export type Plugin = (proxy: httpProxy, options: Options) => void;

export interface Options extends httpProxy.ServerOptions {
/**
* Narrow down requests to proxy or not.
Expand All @@ -32,6 +34,10 @@ export interface Options extends httpProxy.ServerOptions {
| { [regexp: string]: string }
| ((path: string, req: Request) => string)
| ((path: string, req: Request) => Promise<string>);
/**
* Plugins have access to the internal http-proxy instance to customize behavior.
*/
plugins?: Plugin[];
router?:
| { [hostOrPath: string]: httpProxy.ServerOptions['target'] }
| ((req: Request) => httpProxy.ServerOptions['target'])
Expand Down
43 changes: 43 additions & 0 deletions test/e2e/plugins.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { createProxyMiddleware, createApp } from './test-kit';
import * as request from 'supertest';
import { getLocal, Mockttp } from 'mockttp';
import type { Options, Plugin } from '../../src/types';

describe('E2E Plugins', () => {
let mockTargetServer: Mockttp;

beforeEach(async () => {
mockTargetServer = getLocal();
await mockTargetServer.start();
});

afterEach(async () => {
await mockTargetServer.stop();
});

it('should register a plugin and access the http-proxy object', async () => {
let proxyReqUrl: string;
let responseStatusCode: number;

mockTargetServer.forGet('/users/1').thenReply(200, '{"userName":"John"}');

const simplePlugin: Plugin = (proxy) => {
proxy.on('proxyReq', (proxyReq, req, res, options) => (proxyReqUrl = req.url));
proxy.on('proxyRes', (proxyRes, req, res) => (responseStatusCode = proxyRes.statusCode));
};

const config: Options = {
target: `http://localhost:${mockTargetServer.port}`,
plugins: [simplePlugin], // register a plugin
};
const proxyMiddleware = createProxyMiddleware(config);
const app = createApp(proxyMiddleware);
const agent = request(app);

const response = await agent.get('/users/1').expect(200);

expect(proxyReqUrl).toBe('/users/1');
expect(response.text).toBe('{"userName":"John"}');
expect(responseStatusCode).toBe(200);
});
});

0 comments on commit a8f7fde

Please sign in to comment.