How to retrieve detail of HTTP response error - javascript

I've got a node.js application that is making some https requests to a ReST web service.
I want to do something that, on the face of it, appears like it should be simple - retrieve the error message that comes back from the web service.
I can get hold of the status code - i.e. 200, 404 etc but not the detail of the error.
The body of the response looks like this:
{
"type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5",
"title" : "Not Found",
"status": "404",
"detail": "Resource not found: X33003"
}
My code looks like this:
var options = {
"method": "POST",
"hostname": "myhost.com",
"port": null,
"path": "/mypath/",
"headers": {
"content-type": "application/json",
"authorization": basicAuthString,
"cache-control": "no-cache"
}
};
try {
var reqWorkSkill = http.request(options, function(res) {
var chunks = [];
res.on("data", function(chunk) {
chunks.push(chunk);
});
res.on("end", function() {
var body = Buffer.concat(chunks);
var response = JSON.parse(body);
console.log("Detail: " + body.detail); // COMES BACK UNDEFINED
});
res.on("error", function(error) {
console.log("Something went wrong with: " + resourceIdArray[i] + " failed: " + error);
});
if(res.statusCode != 200){
// Do some stuff
}
console.log("res status: " + res.statusCode);
console.log("res text: " + res.statusText); // COMES BACK UNDEFINED
});
reqWorkSkill.write(itemToPost);
reqWorkSkill.end();
}
catch (e) {
console.log(e);
}
It would be useful to be able to present what exactly went wrong - i.e the message: Resource not found: X33003 from the JSON above. How can I get hold of that?

You just had the wrong properties of the objects you were calling. First, you were calling body.detail, but body was the Buffer representation. You need to call the detail property on response. Second, you were trying to get the statusTextproperty of the response, but the correct property is statusMessage. Code ends up like this:
var options = {
"method": "POST",
"hostname": "myhost.com",
"port": null,
"path": "/mypath/",
"headers": {
"content-type": "application/json",
"authorization": basicAuthString,
"cache-control": "no-cache"
}
};
try {
var reqWorkSkill = http.request(options, function(res) {
var chunks = [];
res.on("data", function(chunk) {
chunks.push(chunk);
});
res.on("end", function() {
var body = Buffer.concat(chunks);
var response = JSON.parse(body);
console.log("Detail: " + response.detail); // response, not body
});
res.on("error", function(error) {
console.log("Something went wrong with: " + resourceIdArray[i] + " failed: " + error);
});
if(res.statusCode != 200){
// Do some stuff
}
console.log("res status: " + res.statusCode);
console.log("res text: " + res.statusMessage); // statusMessage, not statusText
});
reqWorkSkill.write(itemToPost);
reqWorkSkill.end();
}
catch (e) {
console.log(e);
}
It's always a good idea to console.log (or the equivalent) the object you're trying to access if you're not getting the correct results, that will show you all the properties of the object.

Related

unable to parse json string in node js

I have this below function in which i am calling another function "uploadContentVersion" which is a request POST. This also includes a callback which i am capturing in the below function .
The issue which i am facing is this line "console.log(data)" is giving me result like this
{"id":"11111111111111","success":true,"errors":[]}
But when i am trying to print console.log(data.id) i am getting undefined.Not sure where i am doing wrong.
const createFileFromJSON = async() => {
if (fs.existsSync('./templates/officetemplate.docx')) {
const templateFile = fs.readFileSync('./templates/officetemplate.docx');
//console.log(templateFile.toString('utf8'))
var doc = await handler.process(templateFile, data);
// 3. save output
fs.writeFileSync('./templates/' + data.accPlanId + '.docx', doc);
uploadContentVersion(sfdc_token.access_token, sfdc_token.instance_url, data.accPlanId, function(data) {
var conn = new sf.Connection({});
conn.initialize({
instanceUrl: sfdc_token.instance_url,
accessToken: sfdc_token.access_token
});
console.log(data) -- > {
"id": "11111111111111",
"success": true,
"errors": []
}
console.log(data.id) -- > undefined
attachFileToRecord(conn, data)
})
// console.log(contentversionres)
} else {
console.log('Template is not present..')
}
var uploadContentVersion = function(token, instUrl, fname, callback) {
var options = {
'method': 'POST',
'url': some url,
'headers': {
'Authorization': 'Bearer ' + token,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"VersionData": fs.readFileSync(`./templates/${fname}.docx`).toString('base64')
})
};
request(options, function(error, response) {
if (response.statusCode === 201) {
callback(response.body);
}
if (error) throw new Error(error);
});
}
Your issue appears to be that you are recieving data as a string, not as an Object. In your answer, you responded saying that adding JSON.parse() (mdn) worked. This is because JavaScript interpreters have no way of knowing that you want it treated as an object, so the JSON.parse function was made to fix that. There is also the opposite, JSON.stringify.
I don't know what was the issue. I just passed JSON.parse(response.body).id from request and it solved the issue

Save a response Request.post token in variable

I just need to take the token returned in API to complete a URL. I need to take the response.body and save in a variable to use after.
I'm using the protractor to automation tests, and to open a URL I'm consuming an API that return a token, to be used as a parameter in a URL
describe('TEste API', function(){
var Request = require('request');
it("api Testing in protractor", async function (callback) {
let tokenReturn = "empty";
tokenReturn = Request.post({
"headers": { "content-type": "application/x-www-form-urlencoded" },
"url": "https://corpqa.sts.ford.com/adfs/oauth2/token",
"form": {
"grant_type":'client_credentials',
"client_id":'ad9cdf61-e863-4606-a90a-cf7b7141234',
"client_secret":'QmjeT5UZ0N1M0jOEcggrxgFzw-vrZY2UphAy21d5',
"resource":'urn:age:pcf:sss:dev',
}
}, (error, response, body) => {
if (error) {
return console.dir(error);
}
resp = JSON.parse(response.body);
console.log("inside: " + resp.access_token);
callback();
});
console.log("outside: www.example.com/?token=" + tokenReturn);
});
});//------------------------- end describe
In console show me.
outside:
www.example.com/?token=[object Object]
inside:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IldzZks3Q2FtMDZKY3dkR1Z6a2NiYVUzd21wZyJ9.eyJhdWQiOiJ1cm46YWdlOnBjZjpzdGY6ZGV2IiwiaXNzIjoiaHR0cHM6Ly9jb3JwcWEuc3RzLmZvcmQuY29tL2FkZnMvc2VydmljZXMvdHJ1c3QiLCJpYXQiOjE1NzMyMzIzNjYsImV4cCI6MTU3MzIzNTk2NiwiYXBwdHlwZSI6IkNvbmZpZGVudGlhbCIsImFwcGlkIjoiYWQ5Y2RmNjEtZTg2My00NjA2LWE5MGEtY2Y3YjcxNDE4OTQ1IiwiYXV0aG1ldGhvZCI6Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9hdXRoZW50aWNhdGlvbm1ldGhvZC9wYXNzd29yZCIsImF1dGhfdGltZSI6IjIwMTktMTEtMDhUMTc6MDQ6MjYuMTU5WiIsInZlciI6IjEuMCJ9.kuVfmgvN7_t4h2LB5o6dzTV2hngdapMrWFRPANISg5ayUnqeBMKHI5PWvISddfZ2qjO7kSPXlYVffhjrBhqAxY75EAhLX8hAmHDm_2jl49prtnsnqV-l-zhFaqCyfhEcgtVCRE_GX6EON2pewsX09Vdbn_2uHvh5wcGdWCnontzkZdrf__X8-tuE5R7tHrtge0ZXMdx5bCF7INKzA1YolTwxOOiYNVvZFPDKLRwa4VUf_qTKN5BmLisRVN4gmnTzGTPXjXlHZApRwJAbXR4V7VhtVQ6VcjHuyYIpp_rK0K7kQjwu0FLpE1FHZTNRwvXNI1VqyhGaanx2bM_59NyDgg
I just want the outside result to be equal to the inside with token.
I made some changes but the result change to UNDEFINED instead OBJECT.
Maybe use promises ?
Example:
function requestToServer(){
return new Promise((resovle, reject) => {
Request.post({
"headers": { "content-type": "application/x-www-form-urlencoded" },
"url": "https://corpqa.sts.ford.com/adfs/oauth2/token",
"form": {
"grant_type":'client_credentials',
"client_id":'ad9cdf61-e863-4606-a90a-cf7b7141234',
"client_secret":'QmjeT5UZ0N1M0jOEcggrxgFzw-vrZY2UphAy21d5',
"resource":'urn:age:pcf:sss:dev',
}
}, (error, response, body) => {
if (error) {
return console.dir(error);
}
resp = JSON.parse(response.body);
console.log("inside: " + resp.access_token);
resovle(resp.access_token);
callback();
});
});
}
describe('TEste API', function(){
var Request = require('request');
it("api Testing in protractor", async function (callback) {
let tokenReturn = await requestToServer();
console.log("outside: www.example.com/?token=" + tokenReturn);
});
});//------------------------- end describe

Processing replies from the javascript Fetch API

I'm struggling with dealing with my fetch() POST request. It's working successfully, and I can see the data just fine and work with it - but only within the fetch() call. I want to pass data back to App.js (I keep my fetch() API in its own utility module .js file)... but the timing is off. Based on console log debugging, it looks like the function that contains the fetch is returning to the original call before the fetch fully resolves.
These are the console results. The success/text object is what I return from the N4RecordScan.submit() function which contains my fetch(). Then a few lines later, we see the promise resolve. So my App.js is left hanging with no data.
I'd appreciate any guidance!! I feel like I'm close!
{success: "", text: ""}
Processing final response.
Fetch finished loading: OPTIONS
{argo:gateresponse: {…}, status: "0", statusid: "OK"}
Here'sa snippet from my App.JS which calls and processes the fetch function further down.
processResponse(myResponseObject) {
this.setState({
responseAlerts: this.state.responseAlerts.push(myResponseObject)
});
console.log('Processing final response. '+ myResponseObject.success + ' ' + myResponseObject.text);
}
sendRequest() {
let response = N4RecordScan.submit(this.interpolateRequest(), this.state.server, this.state.endpoint);
this.processResponse(response);
}
Here's the function where my fetch() resides:
export const N4RecordScan = {
submit(data, server, endpoint) {
let headers = new Headers();
let success = '';
let text = '';
headers.append('Content-Type', 'text/xml');
headers.append('SOAPAction', 'basicInvoke');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
let dataPrefix = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:arg="http://www.navis.com/services/argobasicservice"><soapenv:Header/><soapenv:Body><arg:basicInvoke><arg:scopeCoordinateIds>APMT/USLAX/LAX/LAX</arg:scopeCoordinateIds><arg:xmlDoc><![CDATA[';
let dataSuffix = ']]></arg:xmlDoc></arg:basicInvoke></soapenv:Body></soapenv:Envelope>';
data = dataPrefix + data + dataSuffix;
console.log('about to send ' + data);
fetch(server + endpoint, {
body: data,
method: 'POST',
mode: 'cors',
headers: headers,
credentials: 'include'
})
.then(function(response){
return response.text();
/* if (response.status === 200 || response.status === 0) {
// Success!
console.log('Success: ' + response.text());
return {
success: true,
text: response.text()
};
} else {
// Failure!
console.log('Fail: ' + response.statusText);
return {
success: false,
text: response.statusText
};
} */
} )
.then(function(rspText){
// The raw response contains decoded HTML tags... we need to clean that up.
// Remove dashes from the xml responses... the eventual js object wont like them
rspText = rspText.replace(/-/g, "");
// Convert the text response to XML
var parser = new DOMParser;
var dom = parser.parseFromString(
rspText,
'text/html');
var decodedString = dom.body.textContent;
// use the DOMParser browser API to convert text to a Document
var XML = new DOMParser().parseFromString(decodedString, "text/xml");
// and then use #parse to convert it to a JS object
var responseXmlObject = parse(XML);
console.log(responseXmlObject);
success = true;
text = responseXmlObject.messages;
alert(responseXmlObject.messages.messagedetail);
})
.catch(function(error) {
// Networking Failure!
console.log('NetworkFail: ' + error);
success = false;
text = error;
});
//.done();
console.log({
success: success,
text: text
});
return {
success: success,
text: text
};
}
};
The problem is you are mixing async and sync operations, you should be doing
processResponse(myResponseObject) {
this.setState({
responseAlerts: this.state.responseAlerts.push(myResponseObject)
});
console.log('Processing final response. '+ myResponseObject.success + ' ' + myResponseObject.text);
}
sendRequest() {
N4RecordScan.submit(this.interpolateRequest(), this.state.server, this.state.endpoint)
.then(function (response){
this.processResponse(response);
})
}
,
export const N4RecordScan = {
submit(data, server, endpoint) {
let headers = new Headers();
let success = '';
let text = '';
headers.append('Content-Type', 'text/xml');
headers.append('SOAPAction', 'basicInvoke');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
let dataPrefix = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:arg="http://www.navis.com/services/argobasicservice"><soapenv:Header/><soapenv:Body><arg:basicInvoke><arg:scopeCoordinateIds>APMT/USLAX/LAX/LAX</arg:scopeCoordinateIds><arg:xmlDoc><![CDATA[';
let dataSuffix = ']]></arg:xmlDoc></arg:basicInvoke></soapenv:Body></soapenv:Envelope>';
data = dataPrefix + data + dataSuffix;
console.log('about to send ' + data);
return fetch(server + endpoint, {
body: data,
method: 'POST',
mode: 'cors',
headers: headers,
credentials: 'include'
})
.then(function(response){
return response.text();
/* if (response.status === 200 || response.status === 0) {
// Success!
console.log('Success: ' + response.text());
return {
success: true,
text: response.text()
};
} else {
// Failure!
console.log('Fail: ' + response.statusText);
return {
success: false,
text: response.statusText
};
} */
} )
.then(function(rspText){
// The raw response contains decoded HTML tags... we need to clean that up.
// Remove dashes from the xml responses... the eventual js object wont like them
rspText = rspText.replace(/-/g, "");
// Convert the text response to XML
var parser = new DOMParser;
var dom = parser.parseFromString(
rspText,
'text/html');
var decodedString = dom.body.textContent;
// use the DOMParser browser API to convert text to a Document
var XML = new DOMParser().parseFromString(decodedString, "text/xml");
// and then use #parse to convert it to a JS object
var responseXmlObject = parse(XML);
console.log(responseXmlObject);
success = true;
text = responseXmlObject.messages;
alert(responseXmlObject.messages.messagedetail);
})
.catch(function(error) {
// Networking Failure!
console.log('NetworkFail: ' + error);
success = false;
text = error;
})
.then(function () {
console.log({
success: success,
text: text
});
return {
success: success,
text: text
};
})
//.done();
}
};
You should be returning the promise from fetch inside the submit function so that the function in App.js can wait until fetch is done to do processing

ReferenceError: $http is not defined

I am trying to make a SOAP call through node.js and am getting the below error:
ReferenceError: $http is not defined
Here is my code, everything else appears to work until it fails at the last line:
//Import the `assert` module to validate results.
var assert = require('assert');
var SoapRequestXML='<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:_5="https://clients.mindbodyonline.com/api/0_5">\r\n' +
'<soapenv:Header/>\r\n' +
'<soapenv:Body>\r\n' +
'<_5:GetClasses>\r\n' +
'<_5:Request>\r\n' +
'<_5:SourceCredentials>\r\n' +
'<_5:SourceName>SOURCECREDENTIALS</_5:SourceName>\r\n' +
'<_5:Password>PASSWORD</_5:Password>\r\n' +
'<_5:SiteIDs>\r\n' +
'<_5:int>-99</_5:int>\r\n' +
'</_5:SiteIDs>\r\n' +
'</_5:SourceCredentials>\r\n' +
'</_5:Request>\r\n' +
'</_5:GetClasses>\r\n' +
'</soapenv:Body>\r\n' +
'</soap:Envelope>';
var options = {
//Define endpoint URL.
url: "https://api.mindbodyonline.com/0_5/ClassService.asmx",
//Define body of POST request.
body: SoapRequestXML,
//Define insert key and expected data type.
headers: {
'POST': 'https://api.mindbodyonline.com/0_5/ClassService.asmx?wsdl HTTP/1.1',
'Accept-Encoding': 'gzip,deflate',
'Content-Type': 'text/xml;charset=UTF-8',
'SOAPAction': '"http://clients.mindbodyonline.com/api/0_5/GetClasses"',
'Content-Length': '594',
'Host': 'api.mindbodyonline.com',
'Connection': 'Keep-Alive',
'User-Agent': 'Apache-HttpClient/4.1.1 (java 1.5)'
}
};
//Define expected results using callback function.
function callback(error, response, body) {
//Log status code to Synthetics console.
console.log(response);
//Verify endpoint returns 200 (OK) response code.
assert.ok(response.statusCode == 200, 'Expected 200 OK response');
//Parse JSON received from Insights into variable.
//
var parseString = require('xml2js').parseString;
var XMLReSULT = response.body;
parseString(XMLReSULT, function (err, result) {
console.dir(result);
});
//Log end of script.
console.log("End reached");
}
//Make GET request, passing in options and callback.
$http.post(options, callback);
Any help is appreciated, I am very new at this.
Like previous comments implied, $http is not defined, and you cant use var $http = require('http') because nodes http does not have a post method. You will need to do a little refactoring. I think you're looking for something like this.
var assert = require('assert')
var http = require('http')
var parseString = require('xml2js').parseString;
var SoapRequestXML='<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:_5="https://clients.mindbodyonline.com/api/0_5">\r\n' +
'<soapenv:Header/>\r\n' +
'<soapenv:Body>\r\n' +
'<_5:GetClasses>\r\n' +
'<_5:Request>\r\n' +
'<_5:SourceCredentials>\r\n' +
'<_5:SourceName>SOURCECREDENTIALS</_5:SourceName>\r\n' +
'<_5:Password>PASSWORD</_5:Password>\r\n' +
'<_5:SiteIDs>\r\n' +
'<_5:int>-99</_5:int>\r\n' +
'</_5:SiteIDs>\r\n' +
'</_5:SourceCredentials>\r\n' +
'</_5:Request>\r\n' +
'</_5:GetClasses>\r\n' +
'</soapenv:Body>\r\n' +
'</soap:Envelope>';
var options = {
hostname: 'api.mindbodyonline.com',
port: 80,
path: '/0_5/ClassService.asmx',
method: 'POST',
headers: {
'Accept-Encoding': 'gzip,deflate',
'Content-Type': 'text/xml;charset=UTF-8',
'SOAPAction': '"http://clients.mindbodyonline.com/api/0_5/GetClasses"',
'Content-Length': '594',
'Connection': 'Keep-Alive',
'User-Agent': 'Apache-HttpClient/4.1.1 (java 1.5)'
}
}
var req = http.request(options, (res) => {
var data;
res.setEncoding('utf8');
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
parseString(data, function(err, result) {
console.log(result);
});
console.log('End reached')
});
});
req.on('error', (e) => {
console.log(`problem with request: ${e.message}`);
});
req.write(SoapRequestXML);
req.end();

Arguments passed from request library are received but they aren't received when the arguments are sent from URL

I have a node.js server and I'm making GET requests.
The arguments passed using Python's requests and JavaScripts's request are received properly.
// Python
requests.get(url, data=data)
// JS
request.get({url: url, form:form}, function(){})
But the data is not received when I make the request from a browser like: url?a=1&b=2.
How do I fix it?
This is the function that I'm using to parse the form data:
function extractData(request, response, callback, options) {
var jsonString = '';
request.on('data', function(data) {
jsonString += data;
});
request.on('end', function() {
data = qs.parse(jsonString);
callback(request, response, data, options);
});
}
data is blank when I pass the arguments from URL.
I hope this will be helpful and below code is working to me
var options = {
host: 'services.com',
path: '/app/server.js/index/',
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': data.length
}
};
var req = https.request(options, function(res) {
var msg = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
msg += chunk;//'chunk' response from server
if(chunk != "available")
{
var mail = {
from: "abc#gmail.com",
to: "ddd#gmail.com",
subject: "Alert! from production server",
html: "<p>Hi Team,</p> <p>Alert! production server is down.</p><p>Thanks,<br/>Maintenance Team</p>"
};
transporter.sendMail(mail, function(error, response){
if(error){
console.log(error);
//res.send({ "result" : "failure" });
}else{
console.log("Message sent: " + response);
//res.send({ "result" : "success" });
}
});
}
});
res.on('end', function() {
//console.log(JSON.parse(msg));
console.log(msg);
});

Categories