From 7c2c31f9d154ad779505e4ef8d7c9e77a4d18b4b Mon Sep 17 00:00:00 2001 From: Seth Carter Date: Fri, 14 Feb 2020 13:45:23 -0600 Subject: [PATCH] feat: async pathRewrite (#397) Allow the path rewriter function to be async --- README.md | 8 ++++++ src/http-proxy-middleware.ts | 6 ++--- src/types.ts | 3 ++- test/types.spec.ts | 5 ++++ test/unit/path-rewriter.spec.ts | 43 +++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9bfd3a27..8b7841de 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/src/http-proxy-middleware.ts b/src/http-proxy-middleware.ts index ca113327..c6fe7598 100644 --- a/src/http-proxy-middleware.ts +++ b/src/http-proxy-middleware.ts @@ -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') { @@ -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; diff --git a/src/types.ts b/src/types.ts index 7aef997e..06ff4f1d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -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); router?: | { [hostOrPath: string]: string } | ((req: IRequest) => string) diff --git a/test/types.spec.ts b/test/types.spec.ts index 64a0fdba..671ae47e 100644 --- a/test/types.spec.ts +++ b/test/types.spec.ts @@ -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', () => { diff --git a/test/unit/path-rewriter.spec.ts b/test/unit/path-rewriter.spec.ts index f42d7a88..b848782d 100644 --- a/test/unit/path-rewriter.spec.ts +++ b/test/unit/path-rewriter.spec.ts @@ -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', () => { @@ -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); + }); }); });