Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

Creating a API proxy having both URI and query param

Hello,

Can we create an API proxy where we have a URI and a query param at the end? for example:
https://www.abc.com/V2/DEMO/param1/{param1}/param2/{param2}?queryParam={queryParam},

where https://www.abc.com/V2/example/ is the base path

and the HTTPTargetConnection path is "/services/apexrest/vlocity_cmt/v1/integrationprocedure/DEMO_VIP?param1={VariablePrefix.param1}&param2={VariablePrefix.param2}&queryParam={VariablePrefix.queryParam}"

 

Any help would be appreciated.!
thanks in advance.!

Solved Solved
0 6 1,636
1 ACCEPTED SOLUTION

Here's a working example (attached).

To see it working, first deploy it into an environment, then invoke the proxy like this: 

curl -i $myhostname/ev-and-qparam-mapping/agreementId/A-12345/catalog/Cat-ABC/offer/Offer456-P

 

You can start a trace(Debug) session to see the extracted variables, and to see the request that gets assembled and sent to the back end. 

View solution in original post

6 REPLIES 6

Yes, you can remap URLs in that way.

You can extract segments from the inbound URL path, and then insert them as query params for the outbound URL path.

The way to do it:

  • In the request flow, use ExtractVariables and the URIPath element to extract the path segments you want into variables.
  • In the target flow, set the variable target.copy.path_suffix to false (Using AssignMessage)
  • Also in the target flow, use another AssignMessage policy (or the same one) to set the query params
  • Use a fixed path of /services/apexrest/vlocity_cmt/v1/integrationprocedure/DEMO_VIP in the HTTPTargetConnection

You can google for any of these to get more hints.

As a hint, here's how you would extract path segments. Attach this to the proxy request flow.

 

<ExtractVariables name='EV-PathSegments'>
   <Source>request</Source>
   <VariablePrefix>extracted</VariablePrefix>
   <URIPath>
      <!-- put the extracted values into extracted.param1 and extracted.param2 -->
      <!-- The Pattern is matched against pathsuffix (what comes AFTER the basepath) -->
      <Pattern ignoreCase='true'>/param1/{param1}/param2/{param2}</Pattern>
      <!-- result is: setting extracted.param1 and extracted.param2, IF THE PATH MATCHES THIS PATTERN -->
   </URIPath>
   <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</ExtractVariables>

 

And then the AssignMessage that you must attach to the target flow looks something like this

 

<AssignMessage name='AM-1'>
  <AssignVariable>
    <Name>target.copy.pathsuffix</Name>
    <Value>false</Value>
  </AssignVariable>
  <Set>
    <QueryParams>
      <QueryParam name='p1'>{extracted.param1}</QueryParam>
      <QueryParam name='p2'>{extracted.param2}</QueryParam>
    </QueryParams>
  </Set>
</AssignMessage>

 

If you want to remap queryparams - in other words for queryparam foo on inbound, if you want that to be queryparam bar on the outbound request, then you need to do that in another AssignMessage setting.

 

<AssignMessage name='AM-2'>
  <!-- save the value of queryparam foo -->
  <AssignVariable>
    <Name>saved.foo</Name>
    <Ref>request.queryparam.foo</Ref>
  </AssignVariable>

  <!-- remove the foo queryparam -->
  <Remove>
    <QueryParams>
      <QueryParam name='foo'/>
    </QueryParams>
  </Remove>

  <!-- set the bar queryparam -->
  <Set>
    <QueryParams>
      <QueryParam name='bar'>{saved.foo}</QueryParam>
    </QueryParams>
  </Set>
</AssignMessage>

 

 

Hello,

Thank you for the solution.

 

My exact implementation is that i have a API proxy which ideally has 3 params in the request, which we present as a URI. I want to add a 4th param as a query param. I want to check if the request has the 4th query param, if yes, then the proxy should be of the form - 'V2/DEMO/param1/{param1}/param2/{param2}/param3/{param3}?Param4={Param4}', else it should be 'V2/DEMO/param1/{param1}/param2/{param2}/param3/{param3}'

I did try doing something similar.

In the extract variable, I defined both URI and Query param, like this-

-----------------------------------------------------------------------------------------

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-URI-Variables">
<DisplayName>ExtractVariablesStoreId</DisplayName>
<URIPath name="Test_URI">
<Pattern>**/param1/{param1}/param2/{param2}/param3/{param3}</Pattern>
</URIPath>
<QueryParam name="Test_Query">
<Pattern>{param4}</Pattern>
</QueryParam>
<Source clearPayload="false">request</Source>
<VariablePrefix>varPrefix</VariablePrefix>
</ExtractVariables>

-------------------------------------------------------------------

 

and in the preflow of proxyEndpoint, added a step in the call backend flow, that called a JS policy-

---------------------------------------------------------------------

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
<PreFlow name="PreFlow">
<Request/>
<Response/>
</PreFlow>
<DefaultFaultRule name="default-fault">
<Step>
<Name>Load-CORS-origins</Name>
</Step>
<Step>
<Name>add-cors</Name>
</Step>
</DefaultFaultRule>
<Flows>
<Flow name="CORS Pre Flight Check">
<Description/>
<Request/>
<Response>
<Step>
<Name>Load-CORS-origins</Name>
</Step>
<Step>
<Name>add-cors</Name>
</Step>
</Response>
<Condition>request.verb = "OPTIONS"</Condition>
</Flow>

<!-- implementation done here -->
<Flow name="Call backend">
<Description/>
<Request>
<Step>
<Name>OAuth2-VerifyAccessToken</Name>
</Step>
<Step>
<Name>GetAccessToken</Name>
</Step>
<Step>
<Name>Extract-URI-Variables</Name>
</Step>
<Step>
<Name>JavaScript-1</Name> <!-- added the step here -->
</Step>
<Step>
<Name>ExtractToken</Name>
</Step>
</Request>
<Response>
<Step>
<Name>Load-CORS-origins</Name>
</Step>
<Step>
<Name>add-cors</Name>
</Step>
</Response>
<Condition>request.verb != "OPTIONS"</Condition>
</Flow>
<!-- implementation done here -->

</Flows>
<PostFlow name="PostFlow">
<Request/>
<Response/>
</PostFlow>
<HTTPProxyConnection>
<BasePath>/V2/example/</BasePath>
<VirtualHost>secure</VirtualHost>
</HTTPProxyConnection>
<RouteRule name="route-to-backend">
<Condition>request.verb != "OPTIONS"</Condition>
<TargetEndpoint>backend</TargetEndpoint>
</RouteRule>
<RouteRule name="default">
<Condition>request.verb = "OPTIONS"</Condition>
</RouteRule>
</ProxyEndpoint>

-----------------------------------------------------------------------------------

 

the js resource code is-

--------------------------------------------------------------------------------------

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Javascript async="false" continueOnError="false" enabled="true" timeLimit="200" name="JavaScript-1">
<DisplayName>targetPath1</DisplayName>
<Properties/>
<ResourceURL>jsc://JavaScript-1.js</ResourceURL>
</Javascript>

---------------------------------------------------------------------------------------

var data = context.getVariable("varPrefix.param4");
var TargetPath;
// here i check if the variable extracted is null. If yes, then set the given targetPath. if no, then set the other targetPath, as given below
if(data === null){
context.setVariable("TargetPath","/services/apexrest/vlocity_cmt/v1/integrationprocedure/DEMO_VIP?param1={varPrefix.param1}&amp;param2={varPrefix.param2}&amp;param3={varPrefix.param3}");
}
else{
context.setVariable("TargetPath","/services/apexrest/vlocity_cmt/v1/integrationprocedure/DEMO_VIP?param1={varPrefix.param1}&amp;param2={varPrefix.param2}&amp;param3={varPrefix.param3}&amp;param4={varPrefix.param4}");
}

----------------------------------------------------------------------------------------

 

then finally, i use the set TargetPath in the target Backend postFlow-

-----------------------------------------------------------------------------

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TargetEndpoint name="backend">
<PreFlow name="PreFlow">
<Request>
<Step>
<Name>Assign-Access-Token</Name>
</Step>
</Request>
<Response>
<Step>
<Name>add-cors</Name>
</Step>
</Response>
</PreFlow>
<Flows/>
<PostFlow name="PostFlow">
<Request/>
<Response>
<Step>
<Name>Assign-Message-1</Name>
</Step>
</Response>
</PostFlow>
<HTTPTargetConnection>
<LoadBalancer>
<Server name="URL"/>
</LoadBalancer>
<Path>{TargetPath}</Path> <!-- added here -->
<path/>
</HTTPTargetConnection>
</TargetEndpoint>

-------------------------------------------------------------------

 

but this isn't working, as in I am not able to get any value in the params. 

Please do tell me if this method is correct. And if not, please guide me on how to proceed with this implementation. 

Thanks in advance.!

but this isn't working, as in I am not able to get any value in the params.

If I were working on this, I would want to break it down into separate parts. The ExtractVariables is one part - you need to maker sure that the ExtractVariables policy in the request flow is working as you expect, setting the variables you expect.

The second thing I notice is that in your JS policy, you are setting a value into TargetPath. This value.... then gets set into the path for the outbound request via this snippet.

 

<HTTPTargetConnection>
  <LoadBalancer>
    <Server name="URL"/>
  </LoadBalancer>
  <!-- Path will be set with the value of the TargetPath context variable -->
  <Path>{TargetPath}</Path> <!-- added here -->

  <path/> <!-- omit this. This element is unnecessary and irrelevant. -->

</HTTPTargetConnection>

 

And what is the value you are setting into TargetPath? It is a thing with various pairs of curly braces. But there is nothing in Apigee that automatically de-references the contents of variables, forever and ever, until there are no more curly braces. That de-referencing happens exactly once: in the TEXT value of the Path element within the HTTPTargetConnection.

If your TargetPath holds "/foo" then the path shall be "/foo".

If your TargetPath context variable holds "/a/b/c/{param1}" then Apigee will use as the path, "/a/b/c/{param1}" .

There is no second-pass of indirection.

Therefore I think you can omit the JS step, and simply specify the path in the Path element

 

<HTTPTargetConnection>
  <LoadBalancer>
    <Server name="URL"/>
  </LoadBalancer>
  <!-- Path will be set to the result of evaluating the template -->
  <Path>/services/apexrest/vlocity_cmt/v1/integrationprocedure/DEMO_VIP?param1={varPrefix.param1}&amp;param2={varPrefix.param2}&amp;param3={varPrefix.param3}</Path>
</HTTPTargetConnection>

 

And if you need one more param, optionally, then you may be able to get there by using a policy  something like I showed earlier

<AssignMessage name='AM-Param4'>
  <Set>
    <QueryParams>
      <QueryParam name='param4'>{whatever-variable-you-have}</QueryParam>
    </QueryParams>
  </Set>
</AssignMessage>

Alright... so i specified the path in the path element like -

<HTTPTargetConnection>
<LoadBalancer>
<Server name="AMANDA_URL"/>
</LoadBalancer>
<Path>/services/apexrest/vlocity_cmt/v1/integrationprocedure/MCONLINE_getOffersDetails_V3?Agreementid={agreementId.Agreement}&amp;Catalog={agreementId.Catalog}&amp;Offer={agreementId.Offer}</Path>
</HTTPTargetConnection>

-------------------------------------------------------------------------

and have set a message policy like-

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Assign-query">
<DisplayName>Assign query param</DisplayName>
<Properties/>
<Set>
<QueryParams>
<QueryParam name="productCode">{request.productCode}</QueryParam>
</QueryParams>
</Set>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

-----------------------------------------------------------

 

how do I use extract variables in this case? I have it configured like this-

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ExtractVariables async="false" continueOnError="false" enabled="true" name="Extract-URI-Variables">
<DisplayName>ExtractVariablesStoreId</DisplayName>
<URIPath name="Agreement">
<Pattern>**/agreementId/{Agreement}/catalog/{Catalog}/offer/{Offer}</Pattern>
</URIPath>
<QueryParam name="productCode">
<Pattern>{productCode}</Pattern>
</QueryParam>
<Source clearPayload="false">request</Source>
<VariablePrefix>agreementId</VariablePrefix>
</ExtractVariables>

Here's a working example (attached).

To see it working, first deploy it into an environment, then invoke the proxy like this: 

curl -i $myhostname/ev-and-qparam-mapping/agreementId/A-12345/catalog/Cat-ABC/offer/Offer456-P

 

You can start a trace(Debug) session to see the extracted variables, and to see the request that gets assembled and sent to the back end. 

Thank you very much for this solution. This helped a lot.