4

In the http-proxy-middleware library, the documentation states that you can use the target option to specify where you would like to proxy the request. However, they also allow you to use the router option to specify a function that will be used to functionally resolve the target at runtime.

Docs: https://www.npmjs.com/package/http-proxy-middleware

I am using TypeScript and if I look at the declaration file for the proxy I can see this:

proxy

You can see here that both router and target are nullable. My assumption would be that if you use one, the other can be omitted, but you always need at least 1.

However, if I use the router property like this:

app.use("/pipe", proxy({
    changeOrigin: true,
    router: (req: IIncomingMessageWithCookies) => {
        return "https://www.google.com";
    }
}));

And omit the target, then at runtime I get this error:

> node ./dist/app.js

C:\SkyKick\SkyKick.SEWR\src\node_modules\http-proxy-middleware\lib\config-factory.js:43
    throw new Error(ERRORS.ERR_CONFIG_FACTORY_TARGET_MISSING)
    ^

Error: [HPM] Missing "target" option. Example: {target: "http://www.example.org"}
    at Object.createConfig (C:\SkyKick\SkyKick.SEWR\src\node_modules\http-proxy-middleware\lib\config-factory.js:43:11)
    at new HttpProxyMiddleware (C:\SkyKick\SkyKick.SEWR\src\node_modules\http-proxy-middleware\lib\index.js:17:30)
    at module.exports (C:\SkyKick\SkyKick.SEWR\src\node_modules\http-proxy-middleware\index.js:4:10)
    at Object.<anonymous> (C:\SkyKick\SkyKick.SEWR\src\dist\app.js:8:18)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)

I realized that I can place pretty much anything into target and it will run just fine and my router function is the thing that actually defines the target proxy. Is this just a bug with the library or am I misunderstanding what these 2 options are used for?

Matt Hintzke
  • 6,737
  • 14
  • 47
  • 102

1 Answers1

4

Include both the target and the router property. The router property is there to re-target option.target for specific requests.

import express = require('express');
import proxy = require('http-proxy-middleware');

const app = express();

app.use('/api', proxy({
    target: 'http://www.github.com',
    changeOrigin: true,
    router: function (req: IncomingMessage) {
        return 'http://www.stackoverflow.com'
    }
}));

app.listen(3000);

The target property is optional in the Config type because it is allowed to be empty when we use the shorthand like this:

app.use('/api', proxy('http://www.github.com',
    {
        changeOrigin: true,
        router: function (req: IncomingMessage) {
            return 'http://www.stackoverflow.com'
        }
    }
));
Shaun Luttin
  • 107,550
  • 65
  • 332
  • 414
  • Ok that totally makes sense regarding the nullable properties, however I still don't think I understand what it means to force the developer to re-target like this rather than just having many different ways to define a single property. In my scenario I am wanting to take some arbitrary formatted domain and URL schema and map these origins to many different targets. In that case, I don't have any 1 target to use, do I? – Matt Hintzke Jun 13 '19 at 04:37
  • 2
    I took a look at the source code and do see that `router` basically just overrides the original `options.target` property like I imagined, however it still feels weird being required to add a `target` in this case. I feel like the validation logic should check for the existence of at least one, regardless of implementation. – Matt Hintzke Jun 13 '19 at 06:47
  • Regarding the mapping that you are wanting to do, have you looked at setting the `router` value to an object instead of to a function? – Shaun Luttin Jun 13 '19 at 15:21
  • I can see what you mean about throwing an error when the `target` is empty and the `router` has a value. At first blush, it seems lazy on the part of the original developers. I appreciate, though, that there might be some deeper reason that will reveal itself on further investigation. And, if there is no deeper reason, setting `target` to something like `http://required-target.why` is a reasonable and inexpensive workaround. – Shaun Luttin Jun 13 '19 at 15:22
  • 1
    I don't think I can set it to an object because that would mean there was a finite set of mappings that would take place, when in fact I need the mappings to be completely conventional and scale to any number all based off the schema of the incoming request URI. With that said, simply putting some "garbage" into the `target` property seems to work just fine. I just wanted to confirm that I was understanding how it worked. It seemed farfetched that this was an issue with the library itself seeing how its so widely adopted. Thanks! – Matt Hintzke Jun 13 '19 at 16:23
  • What happens when one wants to get function from another js file? What would be the syntax? – user3102085 Jun 08 '20 at 16:40