Perl module not getting correct web service output - json

Can someone validate this snippet and point out what I might be doing wrong?
This is my code which creates and does a SOAP call.
my $soap = SOAP::Lite->new()->proxy($proxy)->ns('http://example.com', 'ser')->getInfo(
SOAP::Data->name(chronicId => $ticket_num)->prefix('ser'),
SOAP::Data->name(sourceSystem => $sourceSystem)->prefix('ser'),
SOAP::Data->name(outputFormat => $outputFormat)->prefix('ser'),
SOAP::Data->name(uid => $uid)->prefix('ser'),
SOAP::Data->name(username => $username)->prefix('ser'),
SOAP::Data->name(guid => $guid)->prefix('ser')
);
$results = $soap->call($method);
This is the result I get, when I use a test script to execute the above code.
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getChronicInfoResponse xmlns:ns="http://example.com">
<ns:return xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">
{
"UID":"abc1234",
"GUID":"",
"CHRONICID":123,
"OUTPUTFORMAT":"json",
"USERNAME":"xyz",
"STATUS_SUB_CODE_NAME":"Active",
"SOURCESYSTEM":"abc",
"STATUS_NAME":"Open"
}
</ns:return>
</ns:getChronicInfoResponse>
</soapenv:Body>
</soapenv:Envelope>
However when I try to read the web server response into a variable and print it out, all I get is a 1 (it's not empty though) nothing else. The output is supposed to be in JSON, as shown above, which I would then need to parse.
Any guesses what I might be doing wrong? I am new to Perl so it could be a silly thing.

Sorry I missed the updates. I could use the dumper to see a proper response here, seems like I was receiving a hex value while doing a print on the results which was not right.
The dumper returns a JSON string like -
{
'return' => '{"ATTUID":"pm304a","GUID":"d353f542-43f6-421b-9573-4c9c39ce77e3","CHRONICID":420,"OUTPUTFORMAT":"json","USERNAME":"m91619","STATUS_SUB_CODE_NAME":"Active","SOURCESYSTEM":"Oasis","STATUS_NAME":"Open"}'
};
Now I am trying to parse this json using JSON:XS - decode_json, but end up in an error which says
Malformed JSON string neither array, object, number, string or atom,......
I think thats because of the 'return' in the string, maybe I can strip it out and then pass to decode?

Related

Typescript HttpClient.post returning bad request from json formatted string

Ok I have been manipulating this string for hours! So any help is greatly appreciated
I am trying to simply make a post call and generate a password. The api is setup to take in a string a parses the json formatted string itself.
private headers = new HttpHeaders({ 'Content-Type': 'application/json' });
constructor(http: HttpClient) {
var url: string = 'https://eus-safeaccounts-test.azurewebsites.net/' + 'passwords/generate';
var body: string = '"{\"regex\":\"[a-zA-Z0-9]\",\"minLength\":8,\"maxLength\":12}"';
http.post<string>(url, body, { headers: this.headers }).subscribe(result => {
this.signUpResponseStr = result["password"];
}, error => console.error(error));
}
This call returns code 400 bad request. (I think because the text is not being seen as json?)
However, if we set body = '""'; then we get a password sent back from the api no problem. It is seen as an empty string on API side and then they give us a password. Exploring further I tried setting body = '"abc"'; because that is a string not following json format. In this case, we DO NOT get bad request 400, but the api recognizes bad json format and returns Invalid Json
My Question:
What should the body string look like for me to send this request? The API is open so anyone can reproduce and the API code shouldn't have anything to do with the 400 bad request issue, as we can see from my explorations, but the code is here https://github.com/nickpavini/SafeAccountsAPI.
Thanks for any help! :)
EDIT: I also tried sending as JSON type and I also tried JSON.stringify() with no luck
Found it. The string is a bit tricky to understand but hopefully this will help others.
body = '"{\\"regex\\":\\"[a-zA-Z0-9]\\",\\"minLength\\":8,\\"maxLength\\":12}"'
In this case it seems that the body contains a string. (the actual string that will be received by the server)
Inside that string, whenever we need the server to see a " that does not close the string, we must pass an actual backslash \\ and then a ". We do not need 3 backslashes in this case because the single quote ' at the beginning makes sure all paranthesis are included.
Note: Test this with the api in question if it seems weird to you. I think it has to do with the api implementation.
Probably body should not be double quoted, and should look instead like...
var body: string = '{"regex":"[a-zA-Z0-9]","minLength":8,"maxLength":12}'

JSON decode failed

Following is the code snippet where I am observing error: "malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "(end of string)") at"
Error observed is at the decode_json line. Can someone point out what is the error?
my $serverurl = "http://mycompany.net/rest/api/2/";
my $username = 'my.email#domain.com';
my $password = "mypassword\#2019";
my $i ;
my $test;
my $headers = {Accept => 'application/json', Authorization => 'Basic ' .encode_base64($username . ':' . $password)};
my $client = REST::Client->new();
my $idartinstance;
my $idartinstance1;
if (!$idartinstance)
{
print " Trying to Connect to URL using REST client interface \n\n";
$idartinstance1 = $client->GET($serverurl."serverinfo",$headers);
$idartinstance = decode_json($idartinstance1->responseContent());
}
When I print $idartinstance, I get this:
REST::Client=HASH(0x8682024)->responseContent()
Does this mean, it is not able to find REST client?
[EDIT] I have modified the script as below and no difference in the errors.
my $serverurl = "https://mycompany.net/rest/api/3/";
my $username = 'my.email#domain.com';
my $password = 'pf9fCdkGXmi4pMHiwIh74A0D';
my $headers = {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password)};
my $client = REST::Client->new();
if (!$idartinstance)
{
print " Trying to Connect to JIRA using REST client interface \n\n";
$client->GET($serverurl."serverInfo", $headers);
print $client->responseContent();
$idartinstance = decode_json($client->responseContent());
}
Now I have used encoded password. Error is same: malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "(end of string)"). Tried accessing "https://mycompany.net/rest/api/3/serverInfo" via web browser and able to get the details.
Once you get a response, you have to check that its what you want.
if( $client->responseCode() eq '200' ){
print "Success\n";
}
You may also want to check that the content-type is what you expect. If it's supposed to be JSON, check that it is:
if( $client->responseHeader('Content-Type') =~ m|\Aapplication/json\b| ) {
print "Got JSON\n";
}
Once you've established that you have what you wanted, pass the message body off to the JSON decoder.
my $data = decode_json($client->responseContent());
You might also try to catch errors where you should have valid JSON but don't. The block eval can handle that (and see the many sources of the proper employment of eval for its best use):
my $data = eval { decode_json(...) };
I find that I tend to get the wrong content in two situations:
the wrong endpoint, from which a 404 handler returns HTML
a captive portal, which also returns HTML
I think you're misreading the documentation for the module. From the synopsis there, the example that most closely resembles yours is the first one:
my $client = REST::Client->new();
$client->GET('http://example.com/dir/file.xml');
print $client->responseContent();
Notice, in particular, that this example does nothing with the return value from GET(). In your example you do the equivalent of this:
my $client = REST::Client->new();
my $resp = $client->GET('http://example.com/dir/file.xml');
print $resp->responseContent();
As it happens, although there is no documented return value from GET() [Update: I was wrong here - see the first comment - but the return value is really only intended for chaining method calls], it actually returns the object that it was passed, so your approach should work. But it's generally a bad idea to not follow the documentation.
So what is actually going wrong? Well, I'm not sure. As I said, your approach should (accidentally) work. But the error message you're getting tells us that what you're passing to decode_json() is a REST::Client object, not a string containing JSON. I don't think that's how your code should work. Perhaps the code you've shown us isn't actually the code you're running.
The best approach to debug this is to follow the advice from Quentin in the first comment on your question - print the value that you're trying to pass to decode_json() before passing it to the function. In fact, that's good general programming advice - originally write out your code step by step, and only combine steps once you know that the individual steps are working correctly.
Using your variable names, I think your code should look like this:
my $client = REST::Client->new();
# ...other code...
$client->GET($serverurl."serverinfo", $headers);
print $client->responseContent();
# And, only once you've established that
# $client->responseContent() returns what
# you expect, you can add this:
$idartinstance = decode_json($client->responseContent());
If the print() statement doesn't show you JSON, then update your question to add whatever is printed and we'll take a further look.

How do I extract a variable from XML using Postman?

I'm trying to extract a SessionId from the XML which is returned from a SOAP API.
I've read through the Postman documentation (several times over) but it wasn't the most helpful in achieving my goal.
What was suggested in a few blogs was to convert the XML to JSON, and then pick out the token and it's value from there, but that didn't help either.
I used the following in my Test:
var jsonObject = xml2Json(responseBody);
postman.setGlobalVariable("Session_Id", jsonObject.SessionID);
The above created the variable "Session_Id" but didn't actually assign a value to it. I'm stumped.
I'm definitely retrieving the data from the API, and it's viewable in Postman's "Body" Response.
To extract a variable from XML using Postman, first convert your XML to JSON, using the xml2Json converter method:
var responseJson = xml2Json(responseBody);
(Where "responseBody" is your xml body.)
Then use the console.log method to output your JSON data, as such:
console.log(responseJson);
Be sure to have followed this tutorial on Enabling Chrome Dev Tools in Postman
Inside your Test Runner, run the test, then right click and "Inspect" anywhere in the Runner. Select the "Console" tab once Chrome's Dev Tools launch. Expand the "Object" part.
Then drill-down (expand) until you see the Property whose data you need.
Thereafter, set the variable by appending each drill-down level to the parameter you want:
postman.setGlobalVariable("Session_Id", responseJson.UserSessionToken.SessionID);
In this case, "responseJson" is the object, "UserSessionToken" was the next level in the drill-down, and SessionId was the parameter I needed within that.
Note: This answer was the correct solution before v7.15.0 of postman. For versions later than this, the accepted answer may not work.
Since Postman v7.15.0 the accepted answer did not work for me (it used to before the update). You have to put the path segments into square brackets.
For example, in the following XML response:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<QuotesPrivateResponse>
<lease-service>
<duration-in-months>24</duration-in-months>
</lease-service>
</QuotesPrivateResponse>
to retrieve the value duration-in-months:
var response = xml2Json(responseBody);
var duration = response["QuotesPrivateResponse"]["lease-service"]["duration-in-months"];
pm.environment.set("duration", duration);
My strong suspicion is that this behaviour is caused when any of the element names contain hyphens.
Postman v7.20.1
I'd like to add my answer since above there are a couple of details that took me a while to solve:
how to cope with a multipart SOAP response
how to manage a JSON object
responseBody definition
Here's the first lines of my XML response to analyze:
------=_Part_694527_1470506002.1584708814081
Content-Type: application/xop+xml;charset=UTF-8;type="text/xml"
Content-Transfer-Encoding: 8bit
Content-ID:
<e3bd82ac-d88f-49d4-8088-e07ff1c8d407>
<?xml version="1.0" encoding="UTF-8" ?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<ns2:GenericResponse xmlns:ns2="http://XXXXXXXX">
<ns2:Service IdcService="XXXXXXXX">
<ns2:Document>
<ns2:Field name="XXXXXXXX:isSetDefault">1</ns2:Field>
<ns2:Field name="XXXXXXXX">CHECKIN_UNIVERSAL</ns2:Field>
After I noticed it was a multipart I've ended up with this Postman Test:
var response = pm.response.text();
var responseBody = response.substr(response.indexOf('<env:'));
pm.test("The body of the response is a valid XML", function () {
pm.expect(xml2Json(responseBody)).to.exist;
});
pm.test("UCM file upload checkin succesfull", function(){
var responseJson = xml2Json(responseBody);
var JsonFields = (responseJson['env:Envelope']['env:Body']['ns2:GenericResponse']['ns2:Service']['ns2:Document']['ns2:Field']);
JsonFields.forEach( field => {
if (field.name == 'StatusMessage'){
console.log("Field = " + field.name);
pm.expect(field.text().to.include("Successfully checked in"));
}
});
});

$http.get messing JSON parameters

I'm comunicating my Rails API with my AngularJS application.
Everything is working great and normal up until the point I have to send parameters in a GET request. This is the Rails controller
def cats
if cat_params[:color]
#cats = Cat.where(... #you know
else
//Do something else
end
private
def cat_params
params.require(:cat).permit(:color)
end
Then from Angular
var kitty = {
cat: {
color: "red"
}
}
$http.get('some URL', { params: kitty }).success.....
By this time, the params hash looks like a stringify JSON
Started GET "some URL?cat=%7B%22color%22:%22red%22%7D" for 127.0.0.1 at 2015-01-28 23:10:24 -0300
Processing by Some_controller as JSON
Parameters: {"cat"=>"{\"color\":\"red\"}", "cat_id"=>"19"}
Cat Load (0.5ms) SELECT "cat".* FROM "cats" WHERE "cat"."id" = 19 LIMIT 1
{"cat"=>"{\"color\":\"red\"}", "format"=>"json", "controller"=>"some_controller", "action"=>"some_action", "cat_id"=>"19"}
Completed 500 Internal Server Error in 95ms
NoMethodError - undefined method `permit' for "{\"cat\":\"red\"}":String:
I'm also sending the Content-Type header, set to 'application/json'.
From Angular's $http.get documentation, I read that if the value of params is something other than a string, it will stringify the JSON object, so the issue is not in the front-end.
I don't think the solution begins with starting JSON parsing the params hash, since I've had no need to do it in the past. It seems to me that strong_parameters is playing dirty, or Rails is ignoring the JSON string. Any ideas what to do next?
I just ran into the same issue. Changing the param serializer solved the issue for me:
$http.get('someURL', {
paramSerializer: '$httpParamSerializerJQLike',
params: {cat: {color: 'red}}
})
Also adding the 'Content-Type': 'application/json' header will not help since it applies to the the body the request.
I used to meet a $http.get problem that when call $http.get('some url', {params:SOME_PARAMS}), SOME_PARAMS could be transformd to key-value params when it is a simple key-value data like {color:'red'}, and it would transform params to json string when it is a complex type like {cat:{color:'red'}}.
So to solve your question, I suggest that add params behind url like:
$http.get('some URL?cat[color]=red').success.....

Send both JSON response and model in Grails

I'm new to Grails and I'm stuck up with a problem. I want to know if there is a way to send both JSON and view and model through "render" in Grails.
I'm using a jQuery Datatable to display data returned from server which is read from JSON returned by the controller. I also need to display error messages on the same view in case of validation failure in form fields. But I'm able to return either only the JSON or model and view using render. I also tried sending the JSON through model itself but it didn't work.
This is my code:-
def hierarchyBreakInstance = new HierarchyBreak(params);
String json = "{\"sEcho\":\"1\",\"iTotalRecords\":0,\"iTotalDisplayRecords\":0,\"aaData\":[]}";
hierarchyBreakInstance.errors.reject(message(code: 'hierarchyBreak.error.division.blank'));
render(view: "hierarchyBreak", model: [hierarchyBreakInstance: hierarchyBreakInstance]);
//render json;
The gsp code:-
<g:hasErrors bean="${hierarchyBreakInstance}">
<div class="errorMessage" role="alert">
<g:eachError bean="${hierarchyBreakInstance}" var="error">
<g:if test="${error in org.springframework.validation.FieldError}" > data-field-id="${error.field}"</g:if>
<g:message error="${error}"/>
</g:eachError>
</div>
</g:hasErrors>
Could you please let me know if there is a way to do this. Thanks!
You can use like this.
def hierarchyBreakInstance = new HierarchyBreak(params);
String json = "{\"sEcho\":\"1\",\"iTotalRecords\":0,\"iTotalDisplayRecords\":0,\"aaData\":[]}";
hierarchyBreakInstance.errors.reject(message(code: 'hierarchyBreak.error.division.blank'));
render(view: "hierarchyBreak", model: [hierarchyBreakInstance: hierarchyBreakInstance,json:json]);
//render json;
Assuming that you are doing a request with some parameters, and need to return if was succesfull or not, and the data to fill the table with ajax.
I will do on that way, use the statuses of the HTTP to mark if it was a problem with the validation(normally we return 400 Bad Request and the message)
Example :
return ErrorSender.sendBadRequest("error validating field $field with value $value")
And the errorsender has a sendBadRequest method
[response: ['message': message, error: "bad_request", status: 400, cause: []], status: 400]
If the request was OK, you only need to respond the data with something like
return [response: results, status: 200]
In the client side you have to have one function if the request was OK to parse result, and one function if request have some validated data problem, database problem or whatever that caused that the request didnĀ“t return a 200(in the example),there are more status codes, you can check on
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
PD: Initial validation should be done on client side.