Browser editor TargetEndpoint rules are stricter than API

Hi,

A team I'm working with has been developing a proxy that has very dynamic backend targets that we aren't able to easily add target servers for. As a result we're using javascript to configure `target.url` in a TargetEndpoint request step.

We ended up with something like:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TargetEndpoint name="AuthTarget">
<PreFlow name="PreFlow">
<Request>
<Step>
<Name>JS-SetURL</Name>
</Step>
</Request>
<Response/>
</PreFlow>

<PostFlow name="PostFlow">
<Request/>
<Response/>
</PostFlow>

<HTTPTargetConnection>
<Path>{target.url}</Path>
<Authentication>
<GoogleIDToken>
<Audience useTargetUrl="true"/>
<IncludeEmail>true</IncludeEmail>
</GoogleIDToken>
</Authentication>
</HTTPTargetConnection>
</TargetEndpoint>

When we deploy from our CI process, this works fine. When a developer then went to pop open the proxy in the web UI to do some debugging, they were then presented with this error:

 
A <HTTPTargetConnection> must have either a <URL> or a <LoadBalancer> backend resource but not both

 So my question is: are we doing something we shouldn't be in the proxy in the first place, or is the editor too restrictive?

I could include <URL>{target.url}</URL> in the proxy definition instead of the Path (which seems to be ignored), however apigee-lint then tells me I should be using target servers, and I don't see a way to mark a single violation as "safe to ignore" via comments so I'd have to disable that lint across the board.

At the moment i'm probably going to switch it to <URL>, and disable the lint across the board.

Thanks!

Eugene

Solved Solved
2 3 226
1 ACCEPTED SOLUTION

We ended up with something like:

<TargetEndpoint name="AuthTarget">
  ..

  <HTTPTargetConnection>
   <Path>{target.url}</Path>
    ...
  </HTTPTargetConnection>
</TargetEndpoint>

Mmmm. Reading carefully, that error message is telling you that you need either a URL element or a LoadBalancer element, but not both. And in your configuration, you show NEITHER. So the error is correct. It is telling you to specify one of those things. You need exactly one of URL or LoadBalancer.

Maybe you have a simple whoopsie where you are using Path where you intend to specify URL?

Even with that change, I think the configuration will not quite be what you want. If you want a dynamic target, you can use JS or some other step in the target request flow (preflow, postflow, or a conditional flow, as long as it's on the REQUEST side of the target**), to set the variable target.url . I suppose that is what your JS-SetURL step is doing. That variable, target.url , when it is set, implicitly overrides anything specified in the URL element of the HTTPTargetConnection. You do not need to explicitly reference that variable in your TargetEndpoint configuration.

So I think you want something like this:

 

<TargetEndpoint name="AuthTarget">
  <PreFlow name="PreFlow">
    <Request>
      <Step>
        <!-- this JS sets the variable target.url -->
        <Name>JS-SetURL</Name>
      </Step>
    </Request>
  </PreFlow>

  <HTTPTargetConnection>
    <URL>https://this.will.be.overriden/by.the.JS.step.in.the.request.flow</URL>
    <Authentication>
      <GoogleIDToken>
        <Audience useTargetUrl="true"/>
        <IncludeEmail>true</IncludeEmail>
      </GoogleIDToken>
    </Authentication>
  </HTTPTargetConnection>
</TargetEndpoint>

 

I use this pattern all the time. Although, I have never used the Authentication element with Audience and useTargetUrl, along with the target.url override. I suppose it will "just work" as expected, but I haven't tried it.

See if this works and see if it avoids the confusing error message that you see in the UI.

To answer your other question - it is possible that the UI is more strict than the API; and it is absolutely true that apigeelint is more strict that the UI. The validation implementations are distinct. Apigeelint in particular looks for style and convention things, that the UI won't check.

**For anyone who does not understand this remark, check the "What are Flows?" page in the Apigee documentation .

View solution in original post

3 REPLIES 3

We ended up with something like:

<TargetEndpoint name="AuthTarget">
  ..

  <HTTPTargetConnection>
   <Path>{target.url}</Path>
    ...
  </HTTPTargetConnection>
</TargetEndpoint>

Mmmm. Reading carefully, that error message is telling you that you need either a URL element or a LoadBalancer element, but not both. And in your configuration, you show NEITHER. So the error is correct. It is telling you to specify one of those things. You need exactly one of URL or LoadBalancer.

Maybe you have a simple whoopsie where you are using Path where you intend to specify URL?

Even with that change, I think the configuration will not quite be what you want. If you want a dynamic target, you can use JS or some other step in the target request flow (preflow, postflow, or a conditional flow, as long as it's on the REQUEST side of the target**), to set the variable target.url . I suppose that is what your JS-SetURL step is doing. That variable, target.url , when it is set, implicitly overrides anything specified in the URL element of the HTTPTargetConnection. You do not need to explicitly reference that variable in your TargetEndpoint configuration.

So I think you want something like this:

 

<TargetEndpoint name="AuthTarget">
  <PreFlow name="PreFlow">
    <Request>
      <Step>
        <!-- this JS sets the variable target.url -->
        <Name>JS-SetURL</Name>
      </Step>
    </Request>
  </PreFlow>

  <HTTPTargetConnection>
    <URL>https://this.will.be.overriden/by.the.JS.step.in.the.request.flow</URL>
    <Authentication>
      <GoogleIDToken>
        <Audience useTargetUrl="true"/>
        <IncludeEmail>true</IncludeEmail>
      </GoogleIDToken>
    </Authentication>
  </HTTPTargetConnection>
</TargetEndpoint>

 

I use this pattern all the time. Although, I have never used the Authentication element with Audience and useTargetUrl, along with the target.url override. I suppose it will "just work" as expected, but I haven't tried it.

See if this works and see if it avoids the confusing error message that you see in the UI.

To answer your other question - it is possible that the UI is more strict than the API; and it is absolutely true that apigeelint is more strict that the UI. The validation implementations are distinct. Apigeelint in particular looks for style and convention things, that the UI won't check.

**For anyone who does not understand this remark, check the "What are Flows?" page in the Apigee documentation .

Reg: the `this.will.be.overridden`, we'll do that; and just disable the lint. Thanks.

Reg: the audience, this is working for us so far, we have a lot of "weird" stuff in the targets themselves.

yes, I think the apigeelint rule TD002 is my least favorite apigeelint rule.