I'm using request module in express to load a json from a link.
var url = 'https://api.github.com/users/google/repos';
request.get({
url: url,
json: true,
headers: {'User-Agent': 'request'}
}, (err, res, data) => {
if (err) {
console.log('Error:', err);
} else if (res.statusCode !== 200) {
console.log('Status:', res.statusCode);
} else {
// data is already parsed as JSON:
console.log(data.length);
}
});
The output of console.log returns a length of 30.
How can i use the parsed JSON globally (data), outside the function? If i use console.log(data.length) outside it says
Cannot read property 'length' of undefined
Thank you!
You can do it like this
function AnyFunction(res){
//do what you want here
console.log(res.length);
}
const options = {
method: 'GET',
uri: 'https://api.github.com/users/google/repos',
json: true,
headers: {'User-Agent': 'request'}
}
request(options)
.then(function (response) {
// Request was successful, use the response object at will
console.log(response.length);
//you can also pass it in a function and do whatever you want
AnyFunction(response);
})
.catch(function (err) {
// Something bad happened, handle the error
console.log('Error:', err);
})
Related
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
I am using this example to make a POST API call to an API: https://nodejs.dev/making-http-requests-with-nodejs#perform-a-post-request. No issues there, it works well.
Next, I wanted to create a function that makes this API call by taking in dynamic connection parameters, headers and payload. Did that and I am able to return the response object from the function so I can detect the response.statusCode, response.statusMessage, etc. Here's my Node.js code:
Module Code
const https = require("https");
function postLendingApplication(connection, data, callback) {
const options = {
hostname: connection.hostname,
port: connection.port,
path: connection.path,
method: connection.method,
headers: connection.headers
};
//console.log(options)
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`);
res.on("data", d => {
process.stdout.write(d);
});
callback(res);
});
req.on("error", error => {
console.error(error);
});
req.write(data);
req.end();
}
exports.postLendingApplication = postLendingApplication;
Invoking the code from another file
const bpc = require("./public-api");
const data = JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
});
const connection = {
hostname: 'jsonplaceholder.typicode.com',
port: 443,
path: '/posts',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
}
}
var response = bpc.postLendingApplication(connection, data, function(response) {
console.log("Inside the calling function");
//console.log(response);
console.log("Status Code: " + response.statusCode);
console.log("Status Message: " + response.statusMessage);
});
Successful console response
statusCode: 201
Inside the calling function
Status Code: 201
Status Message: Created
{
"title": "foo",
"body": "bar",
"userId": 1,
"id": 101
}
Question: In my callback method, I would like to receive the response body (The JSON) as well as the error so I can run some assertions based on the response/body/error that I received. I am not able to figure out how to setup callback in the module method so it can return all 3 values. If you can please help out with that, it would be greatly appreciated.
Here's the Repl URL in case you'd like to take a stab at it online: https://repl.it/#varun_verma/POST-API
I am not 100% on the question you are asking, I personally if you are wanting to use callbacks in this way use two functions one to handle the error and one for the succsessful response
however, you can use object destruction to give you undefined or default it to null if you like for the item not passed back as shown below:
Module Code
const https = require("https");
function postLendingApplication(connection, data, callback) {
const options = {
hostname: connection.hostname,
port: connection.port,
path: connection.path,
method: connection.method,
headers: connection.headers
};
//console.log(options)
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`);
let data = ''
res.on("data", d => {
data += d;
});
res.on('end', () => {
callback({response: res, data});
});
});
req.on("error", error => {
console.error(error);
callback({response: res, error});
});
req.write(data);
req.end();
}
exports.postLendingApplication = postLendingApplication;
Invoking the code from another file
const bpc = require("./public-api");
const data = JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
});
const connection = {
hostname: 'jsonplaceholder.typicode.com',
port: 443,
path: '/posts',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
}
}
var response = bpc.postLendingApplication(connection, data, function({ response, data, error}) {
// if error is not passed back in the object it defaults to undefined
if (error) console.error(error)
console.log("Inside the calling function");
//console.log(response);
console.log("Status Code: " + response.statusCode);
console.log("Status Message: " + response.statusMessage);
});
If I understand your question correctly, you want to have the response, data, and the error passed to the callback. (where you currently only pass the response)
You can pass the data to the callback like so:
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`);
let data = '';
res.on("data", d => {
data += d;
});
res.on('end', () => {
callback(res, data);
});
});
This buffers the data from the response as it comes in into a string and then only when the response ends passes both the response object and the data as a string to the callback. (you can then use JSON.parse in the callback to convert the data string to an object)
Passing the error is more difficult as the error callback is given separately from the response. I would recommend having a separate callback for the error:
function postLendingApplication(connection, data, callback, error_callback) {
...
req.on("error", error => {
console.error(error);
error_callback(error);
});
...
}
However someone else on here may be able to give a better solution for the error.
I have a post request that submits a patient name and the server is supposed to give me back patient_id in response. I get a 200 response back to the client however I don't get the patient_id back which is what I need. When I console log on the server i can see patient.id is generated and there are no errors either. Wonder if there is something I am missing?
Response -
body: (...), bodyUsed: false, headers: Headers {}, ok: true, redirected: false, status: 200, statusText: "OK", type: "basic", url: "http://localhost:4000/patient/add"
//client side post
handleSubmit(e) {
e.preventDefault();
const postUrl = '/patient/add';
fetch(postUrl, {
method: 'POST',
headers: {'Content-Type': 'text/plain'},
body: this.state.patientName
})
.then(response=> {
if (!response.ok) console.log('failed', response);
else console.log(response);
});
}
this.app.post('/patient/add', bodyParser.text(),
this.route_post_patient_add.bind(this));
async route_post_patient_add(req, res) {
/** #type {string} */
const body = req.body;
if (body === undefined) {
logger.warning('Set room patient failed, body missing');
res.sendStatus(400);
return;
}
if (body === "") {
logger.warning(' body is empty');
res.sendStatus(400);
return;
}
try {
const patient_id = await this.save_patient(body);
res.send(patient_id);
console.log(patient_id); //logs the id that is generated
}
catch (err) {
logger.error('Set patient failed, internal error', { err });
res.sendStatus(500);
}
}
The response object in fetch is not the raw body.
You have to call a function and resolve a promise to get the data.
For example:
fetch("foo")
.then(parse_body)
.then(log_data);
function parse_body(response) {
return response.text();
}
function log_data(response_text) {
console.log(response_text);
}
Further reading: MDN: Using Fetch
app.get('/profile/:id', function(req, res){
var options = { method: 'GET',
url: 'https://api.favoriot.com/v1/streams?max=1',
headers:
{ 'cache-control': 'no-cache',
'content-type': 'application/json',
'apikey': 'api key' } };
request(options, function (error, response, body) {
res.render('profile', {data:body});
console.log(body)
});
});
when I run code above, I get this data:
{"debugCode":null,"statusCode":200,"numFound":1,"results":[{"user_id":"xxx510","stream_created_at":"2019-03-05T16:13:01.982Z","stream_developer_id":"f8b8fcb9-6f3e-4138-8c6b-d0a7e8xxxxx#xxxx510","device_developer_id":"raspberryPIxx#xxx510","data":{"distance":"12.4","status":"1"}}]}
how can I make it only display status only?
AFAIK there is no issue with the code as such. Are you sure that you got the distance and status in the data field of body or is it the intended output? By try using their API playground by setting your API key on it. I have rewritten the code using ES6 standards by promisifying request module or you can use the request-promise-native.
function requestPromisified(options) {
return new Promise(function(resolve, reject) {
request(options, function(error, res, body) {
if (!error && res.statusCode == 200) {
resolve(body);
} else {
reject(error);
}
});
});
}
app.get("/profile/:id", async (req, res) => {
const options = {
method: "GET",
url: "https://api.favoriot.com/v1/streams?max=1",
headers: {
"cache-control": "no-cache",
"content-type": "application/json",
apikey: "api key"
}
};
try {
const body = await requestPromisified(options);
console.log(body);
res.render("profile", { data: body });
} catch (error) {
res.status(400).send('Unable to find a profile')
}
});
1) There is no middleware in this example... you're just making a call to get some data.
2) status is available in body.results[0].data.status so just use that instead of the entire body object
I can access the body of the response but I cannot access the body.success
userInfo:function (req,res) {
var users = [];
db.Users.find({},function (err,result) {
result.forEach(function (user) {
users.push(user);
});
res.json({success:true, userList:users});
});
}
info:function (req,res) {
var options = { method: 'GET',
url: config.auth_url + '/info',
headers:
{
'cache-control': 'no-cache'
},
form:
{}
};
request(options, function (error, response, body) {
if (error)
throw new Error(error);
else if (body.success)
res.json(response.body);
else
res.json({success: false, code: 404});
});
}
This is the response.body
{"success":true,"userList":["5895ea3849616b05d89e27ce","58989c0abe93e41816b91eaf","5899e9bfadf35729818b52b7"]}
Is anyone have idea that I can return appropriate json date because I think that its not a valid json so that it give error.
For the Error :
response.body.success = undefined;
JSON.parse(body) will solve your problem as needed.