HTTP Client get request issue

Not applicable

Hi @Mike Dunker @Michael Russo,

I am currently going through the Edge Developer bootcamp, doing exercise 2 in advance proxy development where I am using a javascipt to call out to an API. I don't seem to be getting response from the API, I have tried debugging by printing out some info throughout the javascript, I have posted below the callout javascript, assemble response and the message i am getting in the transactions output when the first javascript is failing.

JavaScript 1

print("One");
var headers = {'Authorization':'Basic dHJhaW5pbmc6bXlwYXNz'}; 
var url = "http://jokeindex.com/services/20/api/jokes"
var myRequest = new Request(url,"GET",headers);
print("two" + headers);
var exchange = httpClient.send(myRequest);
exchange.waitForComplete();
print("three" + exchange);

// AssembleResponse
function dataResponse(data){
  var message = data;
  print("Final Message " + message);
  return message;
}


Output from error

One

two[object Object]

Could you please help me identify what I am doing wrong.

Solved Solved
0 12 2,962
1 ACCEPTED SOLUTION

Hi Jonny,

can you please try executing below code. I guess the part that is missing is retrieving the response using proper method over exchange object.

getdata.js -(credentials removed in the header part)

print("--------------------Get Data Start-------------------");
var headers = {'Authorization':'Basic XXXXXXXXXXX'};
var url = "http://jokeindex.com/services/20/api/joke?jokeid=3229";
var myRequest = new Request(url,"GET",headers);
print("Request object created");
var exchange = httpClient.send(myRequest);
context.session['exchange'] = exchange;
print("Request sent");
print("--------------------Get Data End-------------------");

assembleResponse.js

print("--------------------Assemble Response Start-------------------");
var exchange = context.session['exchange'];
exchange.waitForComplete(1000);
print("Is Sent successfully in Assemble response --> " + exchange.isSuccess());
print("Response Content --> " + exchange.getResponse().content);
//Assign to Apigee response variable
context.setVariable("response.content",exchange.getResponse().content);
print("--------------------Assemble Response End-------------------");

Please see if it works.

Regards,

Santosh

View solution in original post

12 REPLIES 12

Not applicable

Hi @Anil Sagar could you please help out here, thanks.

Yes, sorry you're having trouble. I have some ideas.

Your JS logic is calling out to a remote system (jokeindex.com) . And that takes some time. How much time? I don't know, but let's find out. Here is my test:

$ { time curl -s -H 'Authorization:Basic dHJhaW5pbmc6bXlwYXNz' http://jokeindex.com/services/20/api/jokes ; } 1> /dev/null

real	0m0.748s
user	0m0.006s
sys	0m0.005s

That output says that invoking the GET on jokeindex.com and waiting for the response takes my machine ~ 0.75 seconds, or 750 milliseconds. Most of that time is spent waiting for the response to return.

Why is this relevant? You may not be aware, but the JavaScript policy in Apigee Edge has a default "maximum time to run" of 200 milliseconds. If a JS policy runs for longer than that, Apigee Edge will interrupt the policy and continue with the proxy flow.

What I think is happening is, Your JS code starts and prints "One", it prepares the request and prints "two", and then sends the request. It then begins waiting. We know from our measurement above that the wait will probably be about 750 milliseconds. About 200ms into the wait, the JS step gets interrupted by Apigee Edge, and so the JS step never gets the chance to print "three".

The way to avoid this is to specify to Apigee Edge that the JS ought to be allowed to run longer than 200ms. You can do this with the timeLimit attribute, like this:

<Javascript timeLimit="3000" name="JS-SendMyRequest">
    <ResourceURL>jsc://sendMyRequest.js</ResourceURL>
</Javascript>

This configuration will tell Apigee Edge to allow the JS to run for a maximum of 3000ms, or 3 seconds.

Does this help?

Thanks @DinoThat sorted that and it is going to the website now, but it is saying invalid authentication, am I passing the headers in the correct way?

Hmmm, I can't figure that one out. Your JS code looks correct to me.

Do you have a linux or macos shell? If you try the curl command, like this:

curl -i -H 'Authorization:Basic dHJhaW5pbmc6bXlwYXNz' http://jokeindex.com/services/20/api/jokes

...what result do you see? When I try it from my machine, it works. If the credentials were bad, I would expect that it would fail, regardless of which machine sent the request.

You wrote:

it is saying invalid authentication,

What do you mean by that, exactly? What is the "IT"? and how is it "saying" that? What specific message do you see, and where?

Hi @Dino

Thanks for response, I actually got that sorted it was a mistake at my end as I still had a target endpoint set up, so authentication was failing for that and not my javascript. I have no createda no target route rule and I am facing another problem.

I can't seem to access the context.session variable in the assemble response javascript. Am i setting correctly in the first? I have pasted the 2 javascripts below. and the error being received.

Error

Execution of assembleResponse failed with error: Javascript runtime error: "ReferenceError: "exchange" is not defined. (assembleResponse.js:2)"

getData

print("One");
var headers = {'Authorization':'Basic dHJhaW5pbmc6bXlwYXNz'};
var url = "http://jokeindex.com/services/20/api/joke?jokeid=3229"
var myRequest = new Request(url,"GET",headers);
print("two" + headers);
var exchange = httpClient.send(myRequest);
print("three" + JSON.stringify(exchange));
context.session['exchange'] = exchange;

assembleResponse

print("hello");
var message = context.session[exchange];
message.waitForComplete(1000);
if(message.isSuccess()){
var resp = message.getResponse();
if(resp.status==200) {
context.setVariable('response.content',resp.content.asJSON);
}else{
throw "failure 1" + resp.status;
}
}else{
throw "failure 2" + resp.status;
}
print("Final Message " + message);

Appreciate your help @Dino

Ahh, I see...

ok, now there is a new question.

Looking at your code I can see on line 2 of the "assembleResponse" you are referring to a JavaScript variable called "exchange". This variable is not defined. This is the Message you are getting from the JS runtime error.

Each JS is an independent script.

The "exchange" that was declared and assigned (with the var statement) in the "getData" script is not known in the "assembleResponse" script.

In order to get this to work, you need a common key for both scripts. A common key for the session array.

What I suggest is that you use 'messageid', which is defined here: http://docs.apigee.com/api-services/reference/variables-reference

The code would be something like :

//getData

print("One");
var headers = {'Authorization':'Basic dHJhaW5pbmc6bXlwYXNz'};
var url = "http://jokeindex.com/services/20/api/joke?jokeid=3229"
var myRequest = new Request(url,"GET",headers);
print("two" + headers);
var exchange = httpClient.send(myRequest);
print("three" + JSON.stringify(exchange));
context.session['exchange'] = exchange;

And

// assemblResponse

print("hello");
var exchange = context.session['exchange'];
exchange.waitForComplete(1000);
if(exchange.isSuccess()){
  var resp = exchange.getResponse();
  if(resp.status==200) {
    context.setVariable('response.content',resp.content.asJSON);
  }else{
    throw "failure 1" + resp.status;
  }
}
else{
  throw "failure 2" + resp.status;
}

Not applicable

Hi @Dino

Wont seem to let me reply to your last comment.

Ok so I understand that it isn't accesible outside the script, however in the code you put below I can't see what is done differently with regards to messageid.

I have read the documentation but still not sure how to implement in the scripts.

Thanks,

Jonny

@Dino

It doesn't seem to print "exchange" which should be the response from the first script. So does that mean no response is being returned? Apologies for all the questions.

@Dino

Are you able to check this please?

Jonny

Hi Jonny,

can you please try executing below code. I guess the part that is missing is retrieving the response using proper method over exchange object.

getdata.js -(credentials removed in the header part)

print("--------------------Get Data Start-------------------");
var headers = {'Authorization':'Basic XXXXXXXXXXX'};
var url = "http://jokeindex.com/services/20/api/joke?jokeid=3229";
var myRequest = new Request(url,"GET",headers);
print("Request object created");
var exchange = httpClient.send(myRequest);
context.session['exchange'] = exchange;
print("Request sent");
print("--------------------Get Data End-------------------");

assembleResponse.js

print("--------------------Assemble Response Start-------------------");
var exchange = context.session['exchange'];
exchange.waitForComplete(1000);
print("Is Sent successfully in Assemble response --> " + exchange.isSuccess());
print("Response Content --> " + exchange.getResponse().content);
//Assign to Apigee response variable
context.setVariable("response.content",exchange.getResponse().content);
print("--------------------Assemble Response End-------------------");

Please see if it works.

Regards,

Santosh

thanks @santosh_ghalsasi

that solved it!

Hi @Jonny Frazer ,

Glad that it helped.!

Thanks,

Santosh