Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: async pathRewrite #397

Merged
merged 8 commits into from Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
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
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
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
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
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);
});
});
});