Empty JSON string when getting target response with text/plain as content type and JSON as body

skammili
Participant II

I am receiving JSON string response from target endpoint with Content-Type as "text/plain; charset=UTF-8". Here is the RAW raw response from target endpoint.

HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 194
{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 12,
    "successful" : 12,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }
}
<br>

I need to reformat(extract an array element or nodeset) the JSON string in javascript and send that as new response.

I am getting following error.

Execution of ConstructResponse failed with error: Javascript runtime error: "SyntaxError: Empty JSON string. (ConstructResponse.js:10)"

Here is my javascript code. I have added javascript step under Proxy Response flow. I am able to get headers count successfully but unable to parse response content as JSON.

print("Res content:"+context.getVariable("response.content"));
print("response.headers.count:"+context.getVariable("response.headers.count"));
var newRes = reconstructRes(context.getVariable("response.content"));
context.setVariable("response.content", newRes);
function reconstructRes(body){
    obj = JSON.parse(body);
    print("took:"+obj.took);
    return JSON.stringify(obj);
}
Solved Solved
0 13 12.3K
1 ACCEPTED SOLUTION

skammili
Participant II

I was able to solve my problem by following steps outlined below.

Achieved solution using proxy chaining feature.

Here are the steps.

  1. Created an internal proxy(handles actual target endpoint call).
  2. Called internal proxy from external proxy(consumer facing) using proxy chaining feature.
  3. Then internal proxy calls our target endpoint.
  4. Internal proxy receives the response from Target endpoint with "Content-Type=text/plain; charset=UTF-8" and JSON in response body. NOTE: I can't be able view the response body in Trace session steps as it has hidden/control characters.
  5. Internal proxy override the Content-Type to have value "application/json" and keep the same JSON response body.
  6. External proxy receives response from internal proxy with "Content-Type=application/json" and JSON in response body. NOTE: Message processor did a magic, while it is receiving the response from internal proxy, it filtered all control characters.
  7. Parsed the JSON content in javascript successfully in external proxy response step. I was able to add/delete JSON elements.NOTE: I can be able view the response body throughout the race session.
  8. External proxy sends the response to developer app.

Once again thank you all for your support.

Thanks,
Sanjay

View solution in original post

13 REPLIES 13

Not applicable

Try the following (first stringify it then parse)


var json = JSON.stringify(body);

return JSON.parse(json);

It still not working.

The strange thing is when I print response.content string length I see zero. When I remove this java script I see data in rest client. Actual content length is 194.

stepExecution-stdout Res content length:0

6445-tracelog.jpg

Not applicable

It is working fine for me.

Here is sample code added in JavaScript policy

var body =
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 12,
"successful" : 12,
"failed" : 0
},
"hits" : {
"total" : 0,
"max_score" : null,
"hits" : [ ]
}
}

var json = JSON.stringify(body);
response.content.asJSON = JSON.parse(json);

If I hardcode like in your code then working for me. What is the best place to put javascript policy to edit response received from target endpoint?

But when I use below javascript then its not working, it is showing response.content as null.

var newRes = reconstructRes(context.getVariable("response.content"));


context.setVariable("response.content", newRes);


function reconstructRes(body){
    var jsonbody = JSON.stringify(body);
    
    print("JSON.stringify:"+jsonbody);
    
    obj = JSON.parse(jsonbody);
    
    //print("took:"+obj.took);
    
    return JSON.stringify(obj);
}
<br>

Please try adding JavaScript policy in Postflow.

I am unable to get the target response with Content-Type: text/plain; charset=UTF-8 by using following statements in javascript. All of these showing empty content but actual target response is 194 characters.

context.targetResponse.content

context.getVariable("response.content")

response.content.asJSON

I may be missing something.

Thanks,

Sanjay

Hi Harimohan,

I was able to solve my problem by proxy chaining. Please see my solution in answer section.

Thanks for your support.

Sanjay

Sanjay, try this proxy. apiproxy-sanjay-reformat.zip

It uses as a target, a service that always returns this json:

{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 12,
    "successful" : 12,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }

with a content-type of text/plain; charset=UTF-8. I think this is exactly what your target service returns.

The attached proxy will receive THAT payload, then reformat it, so that it has an appropriate content-type, and also so that the "took" field is removed, an another field is added. Like this:

HTTP/1.1 200 OK
Date: Thu, 15 Feb 2018 20:27:57 GMT
Content-Type: application/json
Content-Length: 225
Connection: keep-alive


{
  "timed_out": false,
  "_shards": {
    "total": 12,
    "successful": 12,
    "failed": 0
  },
  "hits": {
    "total": 0,
    "max_score": null,
    "hits": []
  },
  "stamp": "reformatted at 2018-02-15T20:27:57.425Z"
}

To use this example, deploy that proxy in any organization + environment, then invoke it like this:

curl -i https://ORG-ENV.apigee.net/sanjay-reformat-json/t1 

I think maybe the problem you are experiencing is that your JS step is not placed/ attached correctly in the API Proxy. See how this working example compares to your proxy; it may show you the way.

Thanks Dino. I am testing this now.

6459-trace.jpg

Hi Dino,

Your example working with your target endpoint.

Where as when I embed the same javascript into my proxy its still showing empty response content when I call context.getVariable("response.content"). Content was not showing in trace session also.

When I remove javascript policy then I can see response in my SOAP-UI client.

Please see the screenshot attached.

May be this target response was having some hidden characters which javascript can't intercept/read using context.getVariable("response.content")?

UPDATE: when I point my proxy to your target endpoint then the same javascript can read the content then its working fine, I can see response in SOAP-UI and tracesession as well. So its something about the response content from our target server.

Thanks,

Sanjay

hi Sanjay

Thanks for the update.

You may wish to try to strip the extra characters from the response from your target. Maybe there is a control character or two that is causing the JSON parser to choke.

You could do that with the JS step, prior to calling JSON.parse().

As to exactly what to do , to strip the characters, ... I don't know the answer to that. It will take some experimentation . You may want to use curl to see the exact output from the original target, or some other tool, and examine everything closely.

Maybe use a Javascript debugger - maybe use an electron app to invoke your target, so you can use the Chrome dev tools to closely examine the returned payload and discover what is different.

good luck!

Hi Dino,

I was able to solve my problem by proxy chaining. Please see my solution below in answer section.

Thanks for your support.

Sanjay

skammili
Participant II

I was able to solve my problem by following steps outlined below.

Achieved solution using proxy chaining feature.

Here are the steps.

  1. Created an internal proxy(handles actual target endpoint call).
  2. Called internal proxy from external proxy(consumer facing) using proxy chaining feature.
  3. Then internal proxy calls our target endpoint.
  4. Internal proxy receives the response from Target endpoint with "Content-Type=text/plain; charset=UTF-8" and JSON in response body. NOTE: I can't be able view the response body in Trace session steps as it has hidden/control characters.
  5. Internal proxy override the Content-Type to have value "application/json" and keep the same JSON response body.
  6. External proxy receives response from internal proxy with "Content-Type=application/json" and JSON in response body. NOTE: Message processor did a magic, while it is receiving the response from internal proxy, it filtered all control characters.
  7. Parsed the JSON content in javascript successfully in external proxy response step. I was able to add/delete JSON elements.NOTE: I can be able view the response body throughout the race session.
  8. External proxy sends the response to developer app.

Once again thank you all for your support.

Thanks,
Sanjay