can apigeex proxy perform header & content based routing in an api with below endpoints
1. certain endpoints in api with incoming msg with headervalue1 & headervalue2 combination of values in comparison with predefined json array of values that need to be stored& pulled from kvm & send the request to one backend versus other (like going to blue if matches , else green)
2. certain endpoints in api with incoming msg with body having value1 & value2 combination of values in comparison with predefined json array of values that need to be stored & pulled from kvm & send the request to one backend versus other (like going to blue if matches , else green)
can this be achieved with javascript policy & kvm? if yes, can anyone help with the sample to achieve using context/session variables ?
Solved! Go to Solution.
The short answer is yes.
In general, an Apigee API proxy can route to different targets based on dynamic evaluation of criteria that you specify. The criteria or conditions can examine:
In summary: you can configure Apigee to route requests based on all sorts of things. How does it work? There are two different approaches.
You might want to read up on RouteRules if you're not familiar with the possibilities there. OK, now to your specific questions. In both cases you said
in comparison with predefined json array of values that need to be stored& pulled from kvm
Getting data from the KVM is no problem. I assume you have a good idea for how to do that, and how to format the data. You'll want to cache the data of course, so set the TimeToLive value in the KVM Get policy appropriately. That saves I/O when the proxy operates at scale.
In the first case you said you want to evaluate "header1" and "header2" and then combine that with the routing table obtained from the KVM, to make a routing decision. Depending on how complex the logic is, you may want to rely on JavaScript to encode it. For example, you could do something like this:
var h1 = context.getVariable('request.header.header1');
var h2 = context.getVariable('request.header.header2');
var routingTable = JSON.parse(context.getVariable('thing-retrieved-from-KVM'));
var selected = routingTable[h1] && routingTable[h1][h2];
if (selected) {
context.setVariable('selected-route', selected);
}
else {
context.setVariable('selected-route', 'default');
}
And then set target.url to the appropriate URL for that selected route.
The second case is essentially the same, except you're retrieving data from the request payload. It works basically the same way.
There are lots of other variations possible. Obviously you might have different things in your routing table, so you might need to use different JavaScript to perform the lookups. This is just a simple example, something to start with.
Some time ago I produced an example of dynamic selection of a target URL based on a weighted random approach. That is similar to what you describe here, but slightly different. It may be helpful to you: https://github.com/DinoChiesa/ApigeeEdge-BlueGreen-1
Hi Raghu,
Once you use:
context.setVariable('selected-route', selected);
The variable `selected-route` will be able to be used directly in routing rules:
<RouteRule name="blue">
<Condition>selected-route = "blue"</Condition>
<TargetEndpoint>blue</TargetEndpoint>
</RouteRule>
<RouteRule name="green">
<Condition>selected-route = "green"</Condition>
<TargetEndpoint>green</TargetEndpoint>
</RouteRule>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
The short answer is yes.
In general, an Apigee API proxy can route to different targets based on dynamic evaluation of criteria that you specify. The criteria or conditions can examine:
In summary: you can configure Apigee to route requests based on all sorts of things. How does it work? There are two different approaches.
You might want to read up on RouteRules if you're not familiar with the possibilities there. OK, now to your specific questions. In both cases you said
in comparison with predefined json array of values that need to be stored& pulled from kvm
Getting data from the KVM is no problem. I assume you have a good idea for how to do that, and how to format the data. You'll want to cache the data of course, so set the TimeToLive value in the KVM Get policy appropriately. That saves I/O when the proxy operates at scale.
In the first case you said you want to evaluate "header1" and "header2" and then combine that with the routing table obtained from the KVM, to make a routing decision. Depending on how complex the logic is, you may want to rely on JavaScript to encode it. For example, you could do something like this:
var h1 = context.getVariable('request.header.header1');
var h2 = context.getVariable('request.header.header2');
var routingTable = JSON.parse(context.getVariable('thing-retrieved-from-KVM'));
var selected = routingTable[h1] && routingTable[h1][h2];
if (selected) {
context.setVariable('selected-route', selected);
}
else {
context.setVariable('selected-route', 'default');
}
And then set target.url to the appropriate URL for that selected route.
The second case is essentially the same, except you're retrieving data from the request payload. It works basically the same way.
There are lots of other variations possible. Obviously you might have different things in your routing table, so you might need to use different JavaScript to perform the lookups. This is just a simple example, something to start with.
Some time ago I produced an example of dynamic selection of a target URL based on a weighted random approach. That is similar to what you describe here, but slightly different. It may be helpful to you: https://github.com/DinoChiesa/ApigeeEdge-BlueGreen-1
I was trying to store/cache the column data into KVM but no luck. so the combination of these values would decide which backend to go to. Does this need to be in a json format. I might have max 800 rows in production like this.
IDE | CHM |
0 | 0 |
3 | 72 |
5 | 72 |
8 | 71 |
10 | 72 |
30 | 72 |
kvmadmin api is throwing error if I send it as json. please help
It's common and easy to use a KVM to store JSON, the secret is to not use an index attribute on the get element (e.g. `<Get assignTo="private.params">`).
For example:
<KeyValueMapOperations continueOnError="false" enabled="true" name="KV-GetParams" mapIdentifier="kvm-usage">
<DisplayName>KV-GetParams</DisplayName>
<ExclusiveCache>false</ExclusiveCache>
<ExpiryTimeInSecs>300</ExpiryTimeInSecs>
<Get assignTo="private.params">
<Key>
<Parameter>params</Parameter>
</Key>
</Get>
<Scope>environment</Scope>
</KeyValueMapOperations>
To set the KVM, first use an ExtractVariables to get the request:
<ExtractVariables async="false" continueOnError="false" enabled="true" name="EV-ParamsData">
<DisplayName>EV-ParamsData</DisplayName>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<JSONPayload>
<Variable name="params_update">
<JSONPath>$.[*]</JSONPath>
</Variable>
</JSONPayload>
<Source clearPayload="false">request</Source>
</ExtractVariables>
Then update the KVM:
<KeyValueMapOperations mapIdentifier="kvm-usage" async="false" continueOnError="false" enabled="true" name="KV-UpdateParams">
<DisplayName>KV-UpdateParams</DisplayName>
<ExclusiveCache>false</ExclusiveCache>
<ExpiryTimeInSecs>300</ExpiryTimeInSecs>
<Put override="true">
<Key>
<Parameter>params</Parameter>
</Key>
<Value ref="params_update"/>
</Put>
<Scope>environment</Scope>
</KeyValueMapOperations>
Sample Postman request
curl --location --request POST '{{HOST}}/kvm-usage/params' \
--header 'Content-Type: application/json' \
--data-raw '[
{
"STORE_ID": 42,
"DIVISION_ID": 42
},
{
"STORE_ID": 3,
"DIVISION_ID": 72
}
]'
Hope that helps get you past your KVM issue and Dino's suggestions work for routing.
Thanks Kurt. Was able to update the KVM with the json.
Is there a way to read the javascript output variable in the routerule condition & route to blue versus green?
Is there a way to read the javascript output variable in the routerule condition & route to blue versus green?
Not directly. You would need to extract something out of that JSON and then make a decision. (Maybe both at the same time). But there is no JSONPath capability available in the Condition elements. You'd need to use JavaScript or an AssignMessage with JSONPath to get the information out of the JSON.
Basically trying to read 'selected-route' in the above example provided by you.
var h1 = context.getVariable('request.header.header1'); var h2 = context.getVariable('request.header.header2'); var routingTable = JSON.parse(context.getVariable('thing-retrieved-from-KVM')); var selected = routingTable[h1] && routingTable[h1][h2]; if (selected) { context.setVariable('selected-route', selected); } else { context.setVariable('selected-route', 'default'); }
Does it need a assignmessage policy to read this in a condition in routerule?
Hi Raghu,
Once you use:
context.setVariable('selected-route', selected);
The variable `selected-route` will be able to be used directly in routing rules:
<RouteRule name="blue">
<Condition>selected-route = "blue"</Condition>
<TargetEndpoint>blue</TargetEndpoint>
</RouteRule>
<RouteRule name="green">
<Condition>selected-route = "green"</Condition>
<TargetEndpoint>green</TargetEndpoint>
</RouteRule>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
it works Kurt. Thanks for your help Dino & Kurt.
Hey Raghu,
Now that I understand your use case a bit better, that is:
When I receive a request with specific combinations of header values representing a store id (e.g. x-storedid:4) and a location id (e.g. x-locationid:2) I need to route to different targets (e.g. 4 and 2 --> blue, 8 and 4 --> green, all others --> default).
There's a solution that just uses a KVM. You store the lookup value in the KVM using a composite key made up of the store ID and location ID.
You can do this via InitialEntries in a KeyValueMapOperations policy:
<KeyValueMapOperations name="KV-GetParams" mapIdentifier="kvm-usage">
<InitialEntries>
<Entry>
<Key>
<Parameter>8</Parameter> <!-- store -->
<Parameter>4</Parameter> <!-- location -->
</Key>
<Value>green</Value>
</Entry>
</InitialEntries>
Or using the kvm-admin-v1 API as per legacy docs for Parameter:
curl -X POST -H {{AUTH}}{HOST}}/kvm-admin/v1/organizations/{{ORG}}/environments/{{ENV}}/keyvaluemaps/kvm-usage/entries \
--header 'Content-type: application/json' --header 'Authorization:Bearer {{TOKEN}}' \
--data-raw '{
"key":"4__2",
"value": "blue"
}'
NOTE: the use of "__" to separate the composite key components.
Then in your proxy you merely do a KVM get to assign the value to a variable `private.route_target`
<KeyValueMapOperations name="KV-GetParams" mapIdentifier="kvm-usage">
<Get assignTo="private.route_target">
<Key>
<Parameter ref="request.header.x-storeid"/>
<Parameter ref="request.header.x-divisionid"/>
</Key>
</Get>
And finally in your Proxy Route Rules:
<RouteRule name="blue">
<Condition>private.route_target = "blue"</Condition>
<TargetEndpoint>blue</TargetEndpoint>
</RouteRule>
<RouteRule name="green">
<Condition>private.route_target = "green"</Condition>
<TargetEndpoint>green</TargetEndpoint>
</RouteRule>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
This approach is very efficient as it only needs to use a single KVM get operation.
Hope that helps!
User | Count |
---|---|
1 | |
1 | |
1 | |
1 | |
1 |