Making HTTP call multiple times

Hi,

We have requirement to make HTTP calls multiple times with different data each time. Is there

any policy for that or we need to call from Java Script policy. Please suggest.

Thanks

Tiru

0 8 2,557
8 REPLIES 8

sidd-harth
Participant V

We need more info to answer.

make HTTP calls multiple times with different data each time.

How/Where do you get different data? Is it hardcoded in proxy?

What do you want to do with the responses?

What s the reason to make multiple HTTP calls?

Will the client make a single call which will invoke these multiple calls?

When you say multiple, how many exactly/approx?

Generally speaking, we could use multiple Service callout policies within the proxy to make multiple HTTP calls, you could also use a Javascript. But it depends on your requirements.

@Siddharth Barahalikar data will be coming from the caller. Based on the data(for ex: id) we need to make the back end SOAP call depends on the number(max 10) of id's come in the request and prepare that SOAP format and make the HTTP call each time.

In our case response can be ignored. Basically Asynchronous calls. Client makes the single with number of id's in the request with we need to call multiple times to back end because back end can take only one id at a time. Pleas let me know if you need more info.

I guess Apigee is not the right tool for this use case. Why don't you go with an Integration based tool, if you have one in your architecture?

If the SOAP format is the same for all the ID, then use a Javascript policy to get all the IDs from request and use a loop with SOAP. Check below URL for HTTP implementation using JS

https://docs.apigee.com/api-platform/samples/cookbook/implementing-http-clients-javascript#codingthe...

https://docs.apigee.com/api-platform/antipatterns/wait-for-complete

https://community.apigee.com/questions/33829/not-able-to-do-async-call-to-https-url-using-javas.html

As Siddharth explained, Apigee is not an integration system and so is not ideally suited to this use case.

You CAN configure Apigee to do what you describe, but you'd need to script it in JavaScript using the httpClient.

inbound call might be:

curl -i https://$ORG-$ENV.apigee.net/fanout/t1 \
  -H content-type:application/json -d '{ "ids" : ["A", "B", "C"] }' 

JS policy

<Javascript name='JS-Fanout-1' timeLimit='200' >
  <Properties>
    <Property name='target'>https://mytarget.io</Property>
  </Properties>
  <ResourceURL>jsc://fanout-1.js</ResourceURL>
</Javascript>

JS fan-out logic:

function invokeOne(id, ix, that) {
  var headers = { 'ID-Index' : ix };
  var req = new Request("http://foo", "GET", headers);
  req.url = properties.target + '/oneid/' + id ;
  var exchangeObj = httpClient.send(req);
  // ignore result
}

var payload = JSON.parse(context.getVariable('request.content'));
if (payload.ids) {
  payload.ids.forEach(invokeOne);
}

Probably you want to include some validation and checking in there, to prevent denial of service etc. Also you may want to be careful with the timeLimit attribute.

The result I saw was:

42.3.139.208 - - [10/Jan/2020:20:12:04 +0000] "GET /oneid/C HTTP/1.1" 200 203 "-" "-"

42.3.139.208 - - [10/Jan/2020:20:12:04 +0000] "GET /oneid/B HTTP/1.1" 200 203 "-" "-"

42.3.139.208 - - [10/Jan/2020:20:12:04 +0000] "GET /oneid/A HTTP/1.1" 200 203 "-" "-"

Your case will be different, in that you need to use POST, not GET, and you need to build a SOAP payload. Both of those things are pretty easy to do.

Hi Dino, sorry I am just using javaScript but not that good at it, but on your code, where is the response will be stored?

In the code that I showed, there is no response stored. There is a comment in that code that reads

 

// ignore result

 

That is what it does. If you want to collect and aggregate the results from the various calls you need to take a different approach. This works for aggregating the results for parallel outbound calls:

 

var start = Date.now();
var responses = [];

function indexedOnComplete(index, numberOfCalls, response, error) {
  var prefix = 'jscall.'+ index.toFixed(0);
  context.setVariable(prefix +'.completed-at', String(Date.now() - start));
  if (response) {
    context.setVariable(prefix +'.response-status', response.status);
    // collect the response content
    responses.push(JSON.parse(response.content));
  }
  else {
    context.setVariable(prefix +'.error', 'Whoops: ' + error);
    responses.push(null);
  }

  // check if this is the final response. If so, set result variables in context.
  if (numberOfCalls == responses.length) {
    context.setVariable('jscall.all-done', String(Date.now() - start));
    // all of the responses
    context.setVariable('jscall.aggregated-result',
                        JSON.stringify(responses, null, 2));
  }
}

// invoke one outbound http call, using the callback method
function invokeOne(item, index, cb) {
  var url = properties.target + '?item=' + item ;
  var headers = { 'Item-Index' : index };
  httpClient.send(new Request(url, 'GET', headers), cb);
}

// ====================================================================

var items = properties.items.split(new RegExp('\\s*,\\s*'));
var numberOfCalls = items.length;
context.setVariable('number-of-calls', numberOfCalls.toFixed(0));

items.forEach(function(currentItem, index) {
  context.setVariable('jscall.' + index.toFixed(0) + '.item', currentItem);
  var cb = function(response, error) {
        return indexedOnComplete(index, numberOfCalls, response, error);
      };
  return invokeOne(currentItem, index, cb);
});

 

You need to configure that with properties to tell it what to invoke, and with what. Like so:

 

<Javascript name='JS-Invoke-Calls' timeLimit='4200' >
  <Properties>
    <Property name='target'>https://my-target.example.com/echo</Property>
    <Property name='items'>A,B,C,D,E</Property>
  </Properties>
  <ResourceURL>jsc://invoke-calls-in-parallel.js</ResourceURL>
</Javascript>

 

After the JS callout completes, the context variable jscall.aggregated-result will contain the array of JSON response payloads from the various requests.

Hi Dino, thanks for your code, it works perfectly fine on multiple http calls. Just one thing is, I can't see the jscall.aggregated-result variable in the trace session. I'm checking also the if condition.

(Edited)
Oh, it is caused because I am not passing the api key on the request headers. I'm successfully access the aggregated result! Thank you very much! Thanks also to the author of this thread.

Not applicable

you can use multiple service callouts. if you want inside one policy then you have to go for javascript/java/python.