Secondary endpoint that adds auth

I'm trying to run two proxy endpoints that go to the same target endpoint and one of them adds authentication for me

/images goes to the target's /api/images and this is working fine

What I want to add is /doc/images that also goes to /api/images with basic auth on it.

I have added the basic auth pretty easily, but I'm not having any luck with the changing of the url


I have this in javascript under a conditional step of the default target preflow

newpathsuffix = context.getVariable("proxy.pathsuffix").replace('doc/','');
context.setVariable("proxy.pathsuffix", newpathsuffix);
context.setVariable("target.copy.pathsuffix", true);
context.setVariable("target.pathsuffix", newpathsuffix)

I have also tried it as a step on the proxy flow

<Flow name="get /doc/images">
            <Description/>
            <Request>
                <Step>
                    <Name>JS-rewritedocimages</Name>
                </Step>
            <Request>
            <Response/>
            <Condition>(proxy.pathsuffix MatchesPath "/doc/images") and (request.verb = "GET")</Condition>
        </Flow>

So far it seems that is always going to the target endpoint as /api/doc/images. Looking at the trace it shows the proxy.pathsuffix and the target.pathsuffix as the values I want but with a equal sign with a lash through them

11018-screen-shot-2021-05-20-at-21759-pm.png

0 8 341
8 REPLIES 8

Not applicable

See, as you have specified, you need two proxy endpoints. So create two proxy endpoints.

One is with /image

And another with /doc/images as base path.

In target endpoint set the backend as you want.

This will simply work for you.

The ProxyEndpoint entity in Apigee has a "Base path". Let's say in your case that basepath is /stanton-api .

The proxy will receive messages sent with any path that starts with that basepath. So if you have an inbound request like /stanton-api/images, that ProxyEndpoint will receive it. Likewise if you have a request like /stanton-api/assets, the same proxyendpoint will receive it, because of the basepath.

For any inbound message handled by a proxyendpoint, the part of the path that comes after the basepath is known as the "path suffix". In Conditions, You can get access to this via the context variable "proxy.pathsuffix".

Assuming a basepath of /stanton-api, then...

full url path suffix
/stanton-api/images /images
/stanton-api/assets /assets
/stanton-api/assets/7635 /assets/7635
/stanton-api/doc/images /doc/images

Within the ProxyEndpoint you can use conditional flows to apply different policies... Normally these conditions might check the proxy.pathsuffix variable. But in many cases you don't want to execute different policies depending on the path. If so, you don't need conditional flows at all in the ProxyEndpoint.


BTW, Even if you don't apply conditional policies, you may yet want to use Conditions as a way to "allow list" the paths sent to the upstream. What I mean is like this:

  <Flows>
    <Flow name='t1'>
      <Request/>
      <Response/>
      <Condition>proxy.pathsuffix MatchesPath "/t1" and request.verb = "GET"</Condition>
    </Flow>
    <Flow name='t2'>
      <Request/>
      <Response/>
      <Condition>proxy.pathsuffix MatchesPath "/t2" and request.verb = "POST"</Condition>
    </Flow>
    <Flow name='unknown request'>
      <Request>
        <Step><Name>RF-UnknownRequest</Name></Step>
      </Request>
      <Response/>
    </Flow>
  </Flows>

The TargetEndpoint is the upstream-facing analog to the ProxyEndpoint. This is the entity that allows you to specify an upstream URL. Maybe the upstream is https://foo.abc.com.

You can specify route rules in a proxyendpoint to conditionally select one TargetEndpoint from a set of them, but in the simplest case a ProxyEndpoint always routes to just one TargetEndpoint.

With no configuration change in the API Proxy bundle - no policies that set "target.copy.pathsuffix" or "target.url" and so on - Apigee acts as a "pass through proxy", and as part of that, it will invoke the designated target with a request that appends the proxy path suffix to the configured URL for the TargetEndpoint.

URL specified in TargetEndpoint proxy.pathsuffix effective target.url
https://foo.abc.com /images https://foo.abc.com/images
https://foo.abc.com/api /images https://foo.abc.com/api/images
https://foo.abc.com/api /doc/images https://foo.abc.com/api/doc/images

Using this information, you can see that by combining two proxy endpoints with different basepaths, that both route to the same target endpoint, you can route to the same effective URL. Let's assume

  • ProxyEndpoint A has basepath = /p
  • ProxyEndpoint B has basepath = /p/doc
  • TargetEndpoint T has configured URL = https://foo.abc.com/api
  • Both ProxyEndpoints route to TargetEndpoint T

In that case,

inbound URL proxy endpoint that will handle the request proxy.pathsuffix effective target URL
https://api.inbound.com/p/images A /images https://foo.abc.com/api/images
https://api.inbound.com/p/doc/images B /images https://foo.abc.com/api/images

Thanks for the very detailed answer. I followed it right through and I believe it will work, though there is a complicating factor that I had not mentioned in my original question. The default proxy endpoint already handles several other /doc/* requests that are going off to a different Target Endpoint. They will now all be pulled in to the new Proxy Endpoint. I'll then need to duplicate the pre and postflow steps for both Proxy Endpoints. Do able but lots of changes will need careful checking. I may be some time

I've hit my first hurdle. Since the old proxyendpoint is still there intercepting /weather, it also picks up /weather/doc I've tried adding a condition to it like this, but it won't even save. There seems no way to prioritise the new ProxyEndpoint. What have I missed?

   <ProxyEndpoint name="default">
       <Condition>!(proxy.pathsuffix MatchesPath "/doc/**")</Condition>

hi Craig

There is no way to define a condition at the ProxyEndpoint layer. The distinguisher for ProxyEndpoints is the basepath. You need to specify a single static basepath for each ProxyEndpoint. And those basepaths must be unique (but can be overlapping).

Your original question was something like

  • I'm trying to run two proxy endpoints that go to the same target endpoint and one of them adds authentication
  • /images goes to the target's /api/images and this is working fine
  • I want /doc/images that also goes to /api/images with basic auth on it.

I tried to explain how you can set up multiple proxyendpoints that proxy to the same target. I think we solved that problem.

But what you really want is ... not necessarily two distinct ProxyEndpoints. (and when I use that term, it refers to the specific thing within Apigee configuration). I think what you want is conditional handling of API requests, and maybe you'll handle it in a single ProxyEndpoint.

So let's suppose you use a single proxyendpoint and a single targetendpoint.

It doesn't matter what the ProxyEndpoint basepath will be. Let's assume /inbound-api

And at this point you can introduce multiple conditional flows, like this, within the ProxyEndpoint:

<Flows>
    <Flow name='bare-images'>
      <Request/>
      <Response/>
      <Condition>proxy.pathsuffix MatchesPath "/images/*" and request.verb = "GET"</Condition>
    </Flow>
    <Flow name='images-but-add-auth'>
      <Request>
          ...
      </Request>
      <Response/>
      <Condition>proxy.pathsuffix MatchesPath "/add-auth/images" and request.verb = "GET"</Condition>
    </Flow>
    <Flow name='unknown request'>
      <Request>
        <Step><Name>RF-UnknownRequest</Name></Step>
      </Request>
      <Response/>
    </Flow>
  </Flows><br>

When you receive a Request with /add-auth/images (the second flow), it seems like you want to do 2 things:

  1. encode a basic auth header and inject it into the request header. That takes two steps: the BasicAuthentication policy and maybe the AssignMessage policy. I guess you are already doing this.
  2. Insure that the /add-auth part of the path does not get propagated to the target. You can do this by setting the target.url directly, but only within the TargetEndpoint ! Not in the ProxyEndpojnt. Therefore introduce a conditional flow there.
<!-- put this in the TargetEndpoint under a Flows parent -->
    <Flow name='images-but-add-auth'>
      <Request>
          <Step><Name>BasicAuth-1</Name></Step>
          <Step><Name>JS-ModifyPath</Name></Step>
      </Request>
      <Response/>
      <Condition>proxy.pathsuffix MatchesPath "/add-auth/*" </Condition>
    </Flow>

And the JS for the JS step should be something like this:

context.setVariable('target.copy.pathsuffix', false);


var originalUrl = context.getVariable('target.url');
var pathsuffix = context.getVariable('proxy.pathsuffix');


context.setVariable('target.url', originalUrl + pathsuffix.replace('add-auth/',''));
context.setVariable('request.header.injected', 'hello there');

Thanks Dino. That looks like it should achieve what I need but in the JS being called from the flow (not a preflow or postflow) of the target endpoint, `target.url' is returning null. I'm using a HTTPTargetConnection->LoadBalancer->Server to set the server that the request will actually go to. And in the Trace I still see that little not-an-equal symbol as in my earlier screenshot

ok that's different. You would do that a little differently. don't set the target.url, instead set a variable and refer to it in the Path element within the Target.

<HTTPTargetConnection>
    <Properties>...</Properties>
    <LoadBalancer>
           <Server name="target1"/>
           <Server name="target2"/>
            ...
    </LoadBalancer>
    <Path>{my-custom-path-variable}</Path>
</HTTPTargetConnection>

And the JS would then need to be something like this:

context.setVariable('target.copy.pathsuffix', false);

var pathsuffix = context.getVariable('proxy.pathsuffix');

context.setVariable('my-custom-path-variable', 
      pathsuffix.replace('add-auth/',''));

And possibly, since the JS itself is replacing 'add-auth/', you don't need to call the JS from within a Conditional flow. It would be fine to include it in the PreFlow or PostFlow (request side of course), because that pathsuffix.replace() will be a no-op for paths that don't have 'add-auth/' within them.

Thanks Dino, this worked. It's pretty much the same as our current redirect to another target endpoint solution so I'm glad to see that is recommended by an expert 🙂 It took a little bit of extra trickery because the different target flows having the same response caches didn't seem to be allowed