If you have the need to make asynchronous HTTP requests in your API proxy, here's a convenient way to achieve this within a javascript callout:
var calloutResponse = httpClient.get('http://httpbin.org/get'); context.session['calloutResponse'] = calloutResponse;
Using javascript is flexible and frequently used for synchronous or asynchronous HTTP requests. With the above code snippet, the httpClient request will execute and any further javascript and proxy processing will continue without waiting for the response. The use of context.session['name'] provides a reference for the httpClient object in order to later access. The session reference, calloutResponse, can now be accessed from a different javascript policy later the proxy request/response processing:
var exchange = context.session['calloutResponse']; exchange.waitForComplete(1000); //timeout in milliseconds var responsePayload = exchange.getResponse().content;
Note: the waitForComplete() method is what forces the javascript execution to wait for the response.
Separating the HTTP callout request and response into multiple javascript policies can be powerful when mashing up APIs. A 3rd party API request can begin during the request flow of the proxy, while processing continues to the Target Endpoint request/response. Then, during the response flow of the proxy, you can access the calloutResponse session and mash it in with response.content populated from the Target Endpoint's response. In this scenario, you've allowed Edge to process the 3rd party API callout in parallel to the normal Target Endpoint request/response.
Sweet! Mike, is there a reason we MUST use the context.session thing to store the exchange? Could I just store the exchange in any context variable?eg, in the JS policy on the requesting side,
context.setVariable('asynch.exchange', httpClient.get('http://httpbin.org/get'));
And then retrieve it later from the response flow, referring to that same context variable?
I've never tried that or seen it used, but I'll definitely try it out now to see how it works.
Looks like that works too, but haven't test how truly async this method is (I had tested the other way). I assume it behaves the same since functionally it appears to work the same.
var calloutResponse = httpClient.get('http://httpbin.org/get'); context.setVariable("calloutResponse", calloutResponse);
Trace shows it slightly odd as it's an exchange object:
calloutResponse = com.apigee.javascript.om.http.ScriptableExchange@4177fe57
Here's the code that accesses it like we do with normal flow variables:
var exchange = context.getVariable("calloutResponse"); exchange.waitForComplete(); var responsePayload = exchange.getResponse().content;
Great stuff @Michael. Thanks for this. Btw, Do you know how the waitForComplete() function works to pause the thread? I have a similar requirement, but I am not using the httpClient module. I have some callbacks that might take some time, and I'd like to be able to wait until it has executed.
@Michael Russo @Dino- I am trying to implement the same in Javascript, but stuck how to implement the load balancing for the target HTTP service. Below is my JS:
var myRequest = new Request();
myRequest.url = "http://xyz.com/audit/v1";
//myRequest.url = "http://abc.com/audit/v1";(have to add this as well as load balancing url)
myRequest.method = "POST";
myRequest.body = context.getVariable("AuditRequestPayload.content");
var starttimestamp = context.getVariable("client.received.start.timestamp"); myRequest.body.asXML.StartTimestamp = moment(starttimestamp).format('YYYY/MM/DD - HH:mm:ss.SSS');
var endtimestamp = context.getVariable("system.timestamp"); myRequest.body.asXML.EndTimestamp = moment(endtimestamp).format('YYYY/MM/DD - HH:mm:ss.SSS');
var exchangeObj = httpClient.send(myRequest);
Any help is appreciated. Thanks
Hello @Michael Russo,
I am trying this approach for Mashiing up 3 responses into one and it works perfectly most of the times (when payload size is ~10 MB).
But when the payload size is 18 MB getResponse() is giving undefined and Javascript is failing as "Javascript runtime error: \"TypeError: Cannot read property \"content\" from undefined".
Have you encountered this issue and any suggestions? Appreciate your help.
var responsePayload = exchange.getResponse().content;
Is it because of some buffering problem?
Hi @Michael Russo,
I have similar query and am not able to achieve as I need to pass headers along with the JSON Payload while invoking HTTPS URL asynchronously through javascript.
I have raised a new question in the below link, can you please help me there with solution.
https://community.apigee.com/questions/33829/not-able-to-do-async-call-to-https-url-using-javas.html
Regards
Ravi
Hi @Pradeep Peddi,
I m also trying to do async call to HTTPS url via javascript. I am getting error like you above but if I use just exchange.getResponse(), as below, this error will go.
var responsePayload = exchange.getResponse();
I am facing issue while invoking asynchronously, can you please answer me to my question if you have done this. The link for my question is below,
https://community.apigee.com/questions/33829/not-able-to-do-async-call-to-https-url-using-javas.html
Regards
Ravi