Skip to content

Commit

Permalink
feat: async pathRewrite (#397)
Browse files Browse the repository at this point in the history
Allow the path rewriter function to be async
  • Loading branch information
rsethc authored Feb 14, 2020
1 parent 483911a commit 7c2c31f
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 4 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,14 @@ Providing an alternative way to decide which requests should be proxied; In case

// custom rewriting
pathRewrite: function (path, req) { return path.replace('/api', '/base/api') }

// custom rewriting, returning Promise
pathRewrite: async function (path, req) {
var should_add_something = await httpRequestToDecideSomething(path);
if (should_add_something) path += "something";
return path;
}

```

- **option.router**: object/function, re-target `option.target` for specific requests.
Expand Down
6 changes: 3 additions & 3 deletions src/http-proxy-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export class HttpProxyMiddleware {
// 1. option.router
// 2. option.pathRewrite
await this.applyRouter(req, newProxyOptions);
this.applyPathRewrite(req, this.pathRewriter);
await this.applyPathRewrite(req, this.pathRewriter);

// debug logging for both http(s) and websockets
if (this.proxyOptions.logLevel === 'debug') {
Expand Down Expand Up @@ -157,9 +157,9 @@ export class HttpProxyMiddleware {
};

// rewrite path
private applyPathRewrite = (req: IRequest, pathRewriter) => {
private applyPathRewrite = async (req: IRequest, pathRewriter) => {
if (pathRewriter) {
const path = pathRewriter(req.url, req);
const path = await pathRewriter(req.url, req);

if (typeof path === 'string') {
req.url = path;
Expand Down
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export type Filter =
export interface Options extends httpProxy.ServerOptions {
pathRewrite?:
| { [regexp: string]: string }
| ((path: string, req: IRequest) => string);
| ((path: string, req: IRequest) => string)
| ((path: string, req: IRequest) => Promise<string>);
router?:
| { [hostOrPath: string]: string }
| ((req: IRequest) => string)
Expand Down
5 changes: 5 additions & 0 deletions test/types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ describe('http-proxy-middleware TypeScript Types', () => {
options = { pathRewrite: (path, req) => '/path' };
expect(options).toBeDefined();
});

it('should have pathRewrite Type with async function', () => {
options = { pathRewrite: async (path, req) => '/path' };
expect(options).toBeDefined();
});
});

describe('router', () => {
Expand Down
43 changes: 43 additions & 0 deletions test/unit/path-rewriter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,44 @@ describe('Path rewriting', () => {

expect(rewriter(rewriteFn)).toBe('/123/789');
});

// Same tests as the above three, but async

it('is async and should return unmodified path', () => {
const rewriteFn = async path => {
const promise = new Promise((resolve, reject) => {
resolve(path);
});
const changed = await promise;
return changed;
};

expect(rewriter(rewriteFn)).resolves.toBe('/123/456');
});

it('is async and should return alternative path', () => {
const rewriteFn = async path => {
const promise = new Promise((resolve, reject) => {
resolve('/foo/bar');
});
const changed = await promise;
return changed;
};

expect(rewriter(rewriteFn)).resolves.toBe('/foo/bar');
});

it('is async and should return replaced path', () => {
const rewriteFn = async path => {
const promise = new Promise((resolve, reject) => {
resolve(path.replace('/456', '/789'));
});
const changed = await promise;
return changed;
};

expect(rewriter(rewriteFn)).resolves.toBe('/123/789');
});
});

describe('Invalid configuration', () => {
Expand Down Expand Up @@ -136,5 +174,10 @@ describe('Path rewriting', () => {
// tslint:disable-next-line: no-empty
expect(badFn(() => {})).not.toThrowError(Error);
});

it('should not throw when async function config is provided', () => {
// tslint:disable-next-line: no-empty
expect(badFn(async () => {})).not.toThrowError(Error);
});
});
});

0 comments on commit 7c2c31f

Please sign in to comment.