Is it possible to use computed keys with KeyValueMaps? - apigee

I would like to use KeyValueMaps to store some simple values, but they keys I need to use would be computed at runtime. For example in my 'InitialEntries' I want to do something like this:
<KeyValueMapOperations async="false" continueOnError="false" enabled="true" name="Sandbox-Read-Count">
<DisplayName>Sandbox - Read Count</DisplayName>
<FaultRules/>
<Properties/>
<ExclusiveCache>false</ExclusiveCache>
<ExpiryTimeInSecs>-1</ExpiryTimeInSecs>
<InitialEntries>
<Entry>
<Key>
<Parameter>{variable}.sandbox.calls</Parameter>
</Key>
<Value>0</Value>
</Entry>
</InitialEntries>
<Scope>apiproxy</Scope>
</KeyValueMapOperations>
However, when doing this I get an error when I try to save the policy:
Error while Uploading file for API Test.
messaging.config.beans.InvalidBundle. Errors:[Entity : policy-Sandbox-Read-Count, Invalid Key Names For Entries: [{apikey}.sandbox.calls];]
Is it possible to use computed values in the KeyValueMap policy? Is there a different syntax that I should be using?

I've investigated this. What happens is when you save the proxy with InitialEntries in the apiproxy-scoped KVM, the KVM is immediately created with the initial entries. Therefore, there is no way to use runtime variables, because the priming of the KVM has happened before the proxy ever runs.
You didn't use the mapIdentifier field in your KeyValueMapOperations element (look at the KeyValueMap PUT Sample in the Apigee docs), so the KVM you would create would be named kvmap.
You can use the following management API call to get a list of the KVMs and their contents for a given apiproxy:
GET https://api.enterprise.apigee.com/v1/o/{org}/apis/{apiname}/keyvaluemaps?expand=true
Authorization: Basic {base64 username:password}
Since The InitialEntries section is only used when the proxy is first loaded successfully (even if you change the InitialEntries section and redeploy, no changes will be made if the KVM of that name already exists), I think the usefulness of the InitialEntries section is rather limited. I'd recommend manually priming your KVM's using the management API to initialize the KVM:
PUT https://api.enterprise.apigee.com/v1/o/{org}/apis/{apiname}/keyvaluemaps
Authorization: Basic {base64 username:password}
Content-Type: application/json
{
"entry" : [ {
"name" : "key",
"value" : "0"
} ],
"name" : "{kvmName}"
}

Related

Adding User Defined Interface Data (UDID) to Sabre PNR

I'm trying to add UDID fields to PNRs using the SOAP API. There is no mention of such functionality anywhere in the docs!
So I tried using the SabreCommandLLSRQ endpoint to attach the UD fields, but I don't seem to be able to make any changes, despite receiving a * response.
I've tried the following command using the endpoint:
5.S*RL[record locator]*UD56 [some test value]
For example:
5.S*RLEPLHYN*UD56 YVRYEG
But that also leads to a * response without the PNR actually changing.
Are you sure that's the right UDID format? I've never seen a record locator prepended to a UDID before. If using the SabreCommandLLSRQ endpoint I would expect your format to look like this:
5.S*UD56 [some test value]
There are many UDID formats so I may be wrong there and I know the responses can be quirky. What response do you get in a PNR if you simply enter your format into Sabre Red?
There is also support for itin remarks in the Add Itinerary Remark (AddRemarkLLSRQ), which may be worth implementing for you as well.
I found it in the API too, it is only mentioned in one of many examples in AddRemarkRQ:
If you want it to show up on the itinerary:
<AddRemarkRQ xmlns="http://webservices.sabre.com/sabreXML/2011/10" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="2.1.1">
<RemarkInfo>
<Remark Type="Invoice">
<Text>
U45-111794
</Text>
</Remark>
</RemarkInfo>
</AddRemarkRQ>
If you don't want it to show up on the itinerary:
<AddRemarkRQ xmlns="http://webservices.sabre.com/sabreXML/2011/10" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="2.1.1">
<RemarkInfo>
<Remark Type="Invoice">
<Text>
U*45-111794
</Text>
</Remark>
</RemarkInfo>
</AddRemarkRQ>
I've tested it in both CreatePassengerNameRecordRQ and AddRemarkRQ contexts.

Error trying to use more than 2 waypoints in new Here Routing API 7.2

I have this annoying problem with the new Here Routing API 7.2:
If I want to use more than 2 waypoints (0 and 1) I get error as a responce from the server:
Request:
https://route.api.here.com/routing/7.2/calculateroute.xml?waypoint0=55.67395%2C12.41686&waypoint1=55.6452%2C12.52621&waypoint2=55.9552%2C12.52421&mode=fastest%3Bcar%3Btraffic:disabled%3BboatFerry:-1&language=en_US&verbosemode=0&alternatives=1&app_code=XXXXXX&app_id=XXXXXXXXXX&routeattributes=wp,sm,sc,sh,bb,lg,no
ERROR RESPONSE:
<ns2:Error xmlns:ns2="http://www.navteq.com/lbsp/Routing-Errors/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" type="ApplicationError" subtype="NoRouteFound" xsi:type="ns2:RoutingServiceErrorType">
<Details>Error is NGEO_ERROR_INVALID_PARAMETERS</Details>
<AdditionalData key="error_code">NGEO_ERROR_INVALID_PARAMETERS</AdditionalData>
<MetaInfo>
<Timestamp>2016-02-18T15:30:21Z</Timestamp>
<MapVersion>8.30.61.154</MapVersion>
<ModuleVersion>7.2.66.0-1329</ModuleVersion>
<InterfaceVersion>2.6.21</InterfaceVersion>
</MetaInfo>
</ns2:Error>
If I take away the waypoin2 in above request it aswers ok:
Request:
https://route.api.here.com/routing/7.2/calculateroute.xml?waypoint0=55.67395%2C12.41686&waypoint1=55.6452%2C12.52621&mode=fastest%3Bcar%3Btraffic:disabled%3BboatFerry:-1&language=en_US&verbosemode=0&alternatives=1&&app_code=XXXXXXXXXX&app_id=XXXXXXXXXX&routeattributes=wp,sm,sc,sh,bb,lg,no,legs
OK RESPONSE:
<rtcr:CalculateRoute xmlns:rtcr="http://www.navteq.com/lbsp/Routing-CalculateRoute/4">
<Response>
<MetaInfo>
<Timestamp>2016-02-18T13:38:57Z</Timestamp>
<MapVersion>8.30.61.153</MapVersion>
<ModuleVersion>7.2.65.0-1222</ModuleVersion>
<InterfaceVersion>2.6.20</InterfaceVersion>
</MetaInfo>
<Route>
<Waypoint>
<LinkId>-840260969</LinkId>
<MappedPosition>
<Latitude>55.6739539</Latitude>
<Longitude>12.4166495</Longitude>
</MappedPosition>
<OriginalPosition>
<Latitude>55.6739499</Latitude>
<Longitude>12.41686</Longitude>
</OriginalPosition>
<Type>stopOver</Type>
<Spot>0.5252525</Spot>
<SideOfStreet>left</SideOfStreet>
<MappedRoadName>Hvissingevej</MappedRoadName>
<Label>Hvissingevej</Label>
<ShapeIndex>0</ShapeIndex>
</Waypoint>
<Waypoint>...</Waypoint>
<Mode>...</Mode>
<Shape>...</Shape>
<BoundingBox>
<TopLeft>
<Latitude>55.6739539</Latitude>
<Longitude>12.4158812</Longitude>
</TopLeft>
<BottomRight>
<Latitude>55.6408489</Latitude>
<Longitude>12.5263282</Longitude>
</BottomRight>
</BoundingBox>
<Leg>...</Leg>
<Summary xmlns:rtc="http://www.navteq.com/lbsp/Routing-Common/4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="rtc:RouteSummaryType">
<Distance>11768</Distance>
<TrafficTime>951</TrafficTime>
<BaseTime>951</BaseTime>
<Flags>motorway</Flags>
<Flags>builtUpArea</Flags>
<Flags>park</Flags>
<Text>
..etc
Why does it not work with more that 2 waypoints???
This looks like a big fat bug to me, but I cant find anything about it on the here.com or anywhere on the internet... :((
THIS Request with 3 waypoints used to work in the old version 6.2:
http://route.nlp.nokia.com/routing/6.2/calculateroute.xml?waypoint0=55.67395%2C12.41686&waypoint1=55.6452%2C12.52621&waypoint2=55.9552%2C12.52421&mode=fastest%3Bcar%3Btraffic:disabled%3BboatFerry:-1&language=en_US&verbosemode=0&alternatives=1&app_code=bSU31J0m--3cnUyNdSj4cw&app_id=dj92lxIBAWPAwMtNxCgm&routeattributes=wp,sm,sc,sh,bb,lg,no
OK RESPONSE:
<rtcr:CalculateRoute xmlns:rtcr="http://www.navteq.com/lbsp/Routing-CalculateRoute/4">
<Response>
<MetaInfo>...</MetaInfo>
<Route>
<RouteId>
REM8tfQAAAHRkVz-Q9ZLQGgFhqxu1ShAAAAAYETWS0AAAADAUtUoQAAAAAAAAPB_AAAAAAAA8H-XourNKMKGp1dKLwEVoKaWrTWkAAEAAABcSi8BAQAAAOk1pAABAAAAAADA_wEAAAAAAMD_ZSl--Cc6kst_SH8JSB2PGaiMIQUIAAAAlEh_CQgAAABwhiEFCAAAAAAAAP4PAAAAAAAA_s9seQ_mg7mwYJAXWCYYxLg-_P8yOgx7Z_zGqIBBluHNBoM
</RouteId>
<Waypoint>...</Waypoint>
<Waypoint>...</Waypoint>
<Waypoint>...</Waypoint>
<Mode>
<Type>fastest</Type>
<TransportModes>car</TransportModes>
<TrafficMode>disabled</TrafficMode>
<Feature weight="-1">boatFerry</Feature>
</Mode>
<Shape>...</Shape>
<BoundingBox>
<TopLeft>
<Latitude>55.9671898</Latitude>
<Longitude>12.4158802</Longitude>
</TopLeft>
<BottomRight>
<Latitude>55.6408501</Latitude>
<Longitude>12.5335598</Longitude>
</BottomRight>
</BoundingBox>
<Leg>...</Leg>
<Leg>...</Leg>
<Summary>
<Distance>62581.0</Distance>
<TrafficTime>2916.0</TrafficTime>
<BaseTime>2916.0</BaseTime>
<Flags>motorway</Flags>
</Summary>
..etc
Can please someone help me solve this?
The combination of a via point (using the waypoint2 parameter) and alternative routes (using the alternatives parameter) is not supported within the Routing API as a single request.
The Routing API reference states:
alternatives
Maximum number of alternative routes that will be calculated and
returned. Alternative routes can be unavailable, thus they are not
guaranteed to be returned. If at least one via point is used in a
route request, returning alternative routes is not supported.
So you can either find:
a single route from A to B to C or
a multiple alternate routes A to B without intermediate waypoints.
Of course if you make two separate requests you could find:
A to B with alternative routes then
B to C with alternative routes

How can I configure WSO2 to automatically replace API urls?

I have an API running on http://my_internal_api.com, and I'm exposing it with WSO2, on https://mywso2:8280/my_api.
Everything works just fine, but the REST API is giving off url attributes in json that are formatted for the original server url.
Example:
When retrieving contact info, I get a JSON object:
[{contact_id: 1, url: contact_url}, {}]
This contact_url is in the form: http://my_internal_api.com/contacts/1
It should be: https://mywso2:8280/my_api/contacts/1
Is there a way to solve this? I'm guessing a squence should be used, but I don't know if this is the right approach or I'm trying to reinvent the wheel.
You can add an out sequence using mediation extension[1].There find all occurrence of "my_internal_api.com" and replace by "mywso2:8280".For replacing you string in the payload you can use the script mediator.
<script language="js">
var payload = mc.getPayloadXML().toString();
<property name="PAYLOAD" value="payload"/>
var changedPayload = payload.replace(/http:\/\/my_internal_api.com/, mc.getProperty('apiURL'));
var xml = new XML(newPayLoad);
mc.setPayloadXML(xml);</script>
1.https://docs.wso2.com/display/AM180/Adding+Mediation+Extensions
The easiest way is to use a header mediator to add a X-Forwarded-Host header, like this:
<sequence name="WSO2AM--Ext--In">
<header name="X-Forwarded-Host"
scope="transport"
expression="get-property('transport','Host')"/>
<header name="X-Forwarded-Proto" scope="transport" value="https"/>
</sequence>
This way, most APIs will be able to correctly resolve the host

Defining Multiple Proxy Endpoints

This is probably an unusual case as I'm trying to define a new Proxy Endpoint in an API Proxy.
Let's say I have a default Proxy Endpoint with a Conditional Flow to match /myflow and action == GET and that works fine.
then I defined a new Proxy Endpoint (new_endpoint) with its own Conditional Flow to match /mynewflow and action == GET.
/mynewflow works fine and goes to the new_endpoint as expected.
however
/myflow is also now going to new_endpoint! (i used the Trace tool and confirmed it).
Here is the HTTP Proxy Connection Settings for both:
<HTTPProxyConnection>
<BasePath>/v2</BasePath>
<Properties/>
<VirtualHost>default</VirtualHost>
<VirtualHost>secure</VirtualHost>
</HTTPProxyConnection>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
Is this expected? If it is, how do I make sure that /myflow routes to default Proxy Endpoint?
Looks like you're missing your <RouteRule> in your proxy. Just like the ConditionalFlow, you need a second RouteRule to point to your new target, which would look something like this:
<HTTPProxyConnection>
<BasePath>/v2</BasePath>
<Properties/>
<VirtualHost>default</VirtualHost>
<VirtualHost>secure</VirtualHost>
</HTTPProxyConnection>
<RouteRule name="new_endpoint">
<TargetEndpoint>new_endpoint</TargetEndpoint>
<Condition>(proxy.pathsuffix MatchesPath "/mynewflow")</Condition>
</RouteRule>
<RouteRule name="default">
<TargetEndpoint>default</TargetEndpoint>
</RouteRule>
You don't need to include individual verbs, because we can assume everything to /mynewflow is going to go to the new_endpoint target.
Also, make sure you put the conditional RouteRule above the default RouteRule -- Apigee will match the first one so if default (no condition) is first, you will never match the condition on the remaining rules.
I learned something today: apparently it's HttpProxyConnection/BasePath dictates which Proxy Endpoint is selected
as soon as made sure that the BasePath is different for both endpoints, routing started the way I expected it to.

One API proxy calling two different target endpoints

i have just started working with Apigee.
I want to create one API proxy which will call two target endpoints based on 'if' condition.
i have created an API and added resources to it but the problem is in this case i am getting two API's .
If thetype='abc' target point should be target1
if thetype='xyz' target point should be target2
Can anyone please tell me how to proceed with it ?
Check out the answer to this question. The details of finding the RouteRules is listed there. The ProxyEndpoint documentation will also be helpful.
You can accomplish what you are attempting using this code:
<RouteRule name="routeToTarget1">
<Condition>thetype == "abc"</Condition>
<TargetEndpoint>target1</TargetEndpoint>
</RouteRule>
<RouteRule name="routeToTarget2">
<Condition>thetype == "xyz"</Condition>
<TargetEndpoint>target2</TargetEndpoint>
</RouteRule>
These RouteRules will be evaluated in order.
Note that you probably want the bottom RouteRule to have no condition, which means it will always match. What happens when thetype does not equal "abc" or "xyz"? Assuming target1 is the default, your code would look like this:
<RouteRule name="routeToTarget2">
<Condition>thetype == "xyz"</Condition>
<TargetEndpoint>target2</TargetEndpoint>
</RouteRule>
<RouteRule name="routeToTarget1">
<TargetEndpoint>target1</TargetEndpoint>
</RouteRule>
If you are using the API Proxy Editor UI, then you can do the following:
(1) Choose New / New Resource from the API Proxy Editor toolbar.
You will then see this:
(2) For the input field, Optional Target URL, enter the target URL that corresponds to that resource.
This tool will then generate both a conditional flow for that resource to which you can optionally attach resource-specific policies.
This tool will also add the needed route rule, and your generated XML will look like this:
<ProxyEndpoint name="default">
<RouteRule name="Resource-1">
<Condition>(proxy.pathsuffix MatchesPath "/someResource") and (request.verb = "GET")</Condition>
<HTTPTargetConnection>
<URL>http://myAlternateEndpoint</URL>
</HTTPTargetConnection>
</RouteRule>
....

Resources