httpclient returns the request body instead of the response body

Hi, I'm using a httpCliient.send and successfully retrieving the exchange object. I can see the response body from the target service, and it is populated correctly.

But, I cannot for the life of me send the response to the client - the original body from the client request is returned instead. It seems like the original body is sent back quicker than the request takes to return the data, too...

I have tried:

response.content = exchangeObj.getReponse().content; // Error = {"message":"Cannot set property \"content\" of undefined to \"{\"result\":[{\"number\".... etc

proxy.TargetResponse.content = exchangeObj.getReponse().content; // Error = {"message":"Cannot set property \"content\" of undefined to \"{\"result\":[{\"number\"...etc

context.setVariable("response.content", exchangeObj.getResponse().content); // results in this message in the trace for the javascript variable response.content !={"result":[{"number":"CAS0845403"}]}

Please help, I'm going crazy!!!

Thanks,

Jason

Solved Solved
0 2 783
1 ACCEPTED SOLUTION

hi Jason

Maybe there's a misunderstanding.

Apigee is a pretty flexible product, and sometimes people get side-tracked into trying things a certain way, when there is a much easier way.

Let me step back - start at the beginning.

Within Apigee, you can configure "proxies". The API Proxy acts as a "go between". A client sends a request into Apigee, the proxy receives the request... The proxy (according to your configuration) can examine or modify the request.. and then , in the standard case, the proxy "clones" the request and sends that clone to the upstream (aka backend) system. In Apigee language the upstream is called the "target", and you configure which target an API Proxy will connect to, via the TargetEndpoint entity within the API Proxy. When Apigee receives the Response from the target, the proxy has the option to examine or modify that response, before Apigee automatically relays the response back to the original client.

This video shows the basics.

You seem to be using a JavaScript callout to connect to a remote system. That's certainly something you CAN do, but it's not required in most cases. A common error I see people making is... assuming they ned to write JavaScript and use the httpClient in order to connect to a target. That's unnecessary, most of the time. Use the TargetEndpoint! It will relay the response back to the client as you seem to want.

As I said, you CAN use JavaScript to connect to a remote system. It seems like you are able to use the httpClient, you got the exchange object .... And it will be possible, with some changes within that JS, to copy the response content into the response that eventually gets sent back to the client. (Subject to some constraints) But remember! you probably DO NOT want to do this. Only follow what I am about to suggest if you're certain that you do not want to use the standard Target to connect to the remote system, and you want to use JS to do that, for some reason.

First, don't use the exchangeObject interface. That is still supported, for backward compatibility, but there's a better way, using the callback. I am really sorry that the documentation page for the httpclient still gives so many examples that use the exchange Object. There's a better way. The JS code should look like this:

  function onComplete(response, error) {
    if (response) {
      context.setVariable('response.content', response.content);
    }
    else {
      context.setVariable('response.content', 'Whoops: ' + error);
    }
  }
  var id = context.getVariable('id_to_send');
  var url = 'https://mybackend.example.com/oneid/' + id ;
  var headers = { 'Authorization' : 'my-authorization-string' };
  var req = new Request(url, 'GET', headers);
  httpClient.send(req, onComplete);

But there's a catch - you need to run this in the Response Flow (See here for more on flows). Because when the response flow starts, the response object gets cleared. If you were to run this in the request flow, then... the response object would get _reset_ , wiping out your changes, when control transfers to the response flow.

That will allow you to connect to a backend system from JS., and retrieve the content and pass it bck to the original client.

But there are some pieces missing. You can see my logic copies the response content. What about the headers? what about the status code? I haven't done that in this simple example code. The Target endpoint thing I mentioned above.... propagates all those things correctly into the response object, automatically. If you do things in JavaScript, you would have to add in logic for handling all that stuff.

good luck.

View solution in original post

2 REPLIES 2

hi Jason

Maybe there's a misunderstanding.

Apigee is a pretty flexible product, and sometimes people get side-tracked into trying things a certain way, when there is a much easier way.

Let me step back - start at the beginning.

Within Apigee, you can configure "proxies". The API Proxy acts as a "go between". A client sends a request into Apigee, the proxy receives the request... The proxy (according to your configuration) can examine or modify the request.. and then , in the standard case, the proxy "clones" the request and sends that clone to the upstream (aka backend) system. In Apigee language the upstream is called the "target", and you configure which target an API Proxy will connect to, via the TargetEndpoint entity within the API Proxy. When Apigee receives the Response from the target, the proxy has the option to examine or modify that response, before Apigee automatically relays the response back to the original client.

This video shows the basics.

You seem to be using a JavaScript callout to connect to a remote system. That's certainly something you CAN do, but it's not required in most cases. A common error I see people making is... assuming they ned to write JavaScript and use the httpClient in order to connect to a target. That's unnecessary, most of the time. Use the TargetEndpoint! It will relay the response back to the client as you seem to want.

As I said, you CAN use JavaScript to connect to a remote system. It seems like you are able to use the httpClient, you got the exchange object .... And it will be possible, with some changes within that JS, to copy the response content into the response that eventually gets sent back to the client. (Subject to some constraints) But remember! you probably DO NOT want to do this. Only follow what I am about to suggest if you're certain that you do not want to use the standard Target to connect to the remote system, and you want to use JS to do that, for some reason.

First, don't use the exchangeObject interface. That is still supported, for backward compatibility, but there's a better way, using the callback. I am really sorry that the documentation page for the httpclient still gives so many examples that use the exchange Object. There's a better way. The JS code should look like this:

  function onComplete(response, error) {
    if (response) {
      context.setVariable('response.content', response.content);
    }
    else {
      context.setVariable('response.content', 'Whoops: ' + error);
    }
  }
  var id = context.getVariable('id_to_send');
  var url = 'https://mybackend.example.com/oneid/' + id ;
  var headers = { 'Authorization' : 'my-authorization-string' };
  var req = new Request(url, 'GET', headers);
  httpClient.send(req, onComplete);

But there's a catch - you need to run this in the Response Flow (See here for more on flows). Because when the response flow starts, the response object gets cleared. If you were to run this in the request flow, then... the response object would get _reset_ , wiping out your changes, when control transfers to the response flow.

That will allow you to connect to a backend system from JS., and retrieve the content and pass it bck to the original client.

But there are some pieces missing. You can see my logic copies the response content. What about the headers? what about the status code? I haven't done that in this simple example code. The Target endpoint thing I mentioned above.... propagates all those things correctly into the response object, automatically. If you do things in JavaScript, you would have to add in logic for handling all that stuff.

good luck.

Hi Dino,

You know what? I totally agree 🙂 I had a good use case for using JavaScript, but I jumped straight in with an overly-complex solution and expected to get somewhere fast. It doesn't work like that. It's a new product to me, and the learning curve was a bit steep without taking care of the basics.

So, I've gone back to the basics, and it's all worked out with no need for the JavaScript. I *might* go back there one day, but at the moment, no need.

Whilst I was trying to get the JavaScript to work, I did try out the callback, too (before you replied). Of course, that didn't work either because I'd called the JavaScript from the request, not the response - hence no response object - doh!!!

I've got to thank you for your time providing a full reply, though - it did make me rethink and go back to using the functionality in the system rather than writing my own code.

Cheers,

Jason