Asynchronous HTTP Requests in an API proxy

9 8 10.3K

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.

Comments
DChiesa
Staff

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?

Not applicable

I've never tried that or seen it used, but I'll definitely try it out now to see how it works.

Not applicable

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;
ksprashu
Staff

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.

Not applicable

@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

Not applicable

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?

Not applicable

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

Not applicable

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

Version history
Last update:
‎03-31-2015 03:39 PM
Updated by: