Difficulty with making multiple api / http node.js requests - javascript

Hello I've gotten two api requests to work individually but I'm having a lot of trouble to get them both working on my node.js app. Is there an easy way to make two requests ? I've tried making two requests putting the data into a variable and then rendering both of them but I run into issues with global variables. Any help would be appreciated.
request(url, function (err, response, body) {
if(err){
res.render('index', {weather: null, error: 'Error, please try again'});
} else {
let weather = JSON.parse(body);
if(weather.main == undefined){
res.render('index', {weather: null, error: 'Error, please try again'});
} else {
if (rain == "0,rain"){
let weatherText = `It's ${weather.main.temp} degrees celsius and with wind speeds of ${weather.wind.speed} mph in ${weather.name} ${weather.sys.country}! & ${weather.weather[0].description}` ;
res.render('index', {weather: weatherText, error: null});
}
else{
let weatherText = `It's ${weather.main.temp} degrees celsius and with wind speeds of ${weather.wind.speed} mph in ${weather.name} ${weather.sys.country}!` ;
res.render('index', {weather: weatherText, error: null});
}
}
}
});
request(url2, function (err, response, body) {
if(err){
res.render('index', {news: null, error: 'Error, please try again'});
} else {
let result = JSON.parse(body);
let news = result.articles[0].title
if(news == undefined){
res.render('index', {news: null, error: 'Error, please try again'});
}
else{
res.render('index', {news:news, error: null});
}
}
})

There is no actual need to use promises, although they do simplify code structure, you can just a easily nest requests:
request(url, function(err, response, body) {
request(url2, function(err2, response2, body2) {
// Both request data is available here
})
})
Note that the variable names used in the callback function can be changed here
Should you have a bunch of requests that can be ran independently, look into promise.all

I would use a ‘promise’ to wait until a response has been received from your first request. Once this has happened, you can trigger your second request, (see ‘then’ on the link below). Once your second request returns a result, you can combine the response from both requests, before using the data.
If request B needs to use data from the response of request A, then request A should be first in the chain. This allows you to adjust your second request based on the response from the first e.g. with IF statements. If the two are completely independent, you can pick either request to go first.
There is a section on this link about chaining promises, which should be relevant to what you’re trying to do: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
Details about error handling with promises and ‘catch’ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch

Related

I'm unable to send a response to my react.js using http.get in node

I'm trying to get the temperature data from my node.js backend sent to react.js but i kept getting res.send is not a funtion
Sample code here
app.get("/gettemperature", (req, res) => {
const email = req.query.email;
let stmt = `SELECT * FROM users WHERE email=?`;
let todo = [email];
db.query(stmt, todo, (err, results, fields) => {
if (err) {
console.error(err.message);
}
if(results.length > 0 ){
let id = results[0].id;
let getID = `SELECT * FROM controlModules WHERE deviceowner=?`;
let getidData = [id];
db.query(getID, getidData, (err, resulta, fields) => {
if (err) {
console.error(err.message);
}
if(resulta.length > 0){
let lanip = resulta[0].ipaddress;
let url = "http://"+lanip+"/data";
http.get(url,(res) => {
let body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
try {
let json = JSON.parse(body);
const temp_actual = json.temperature.value;
console.log(temp_actual);
res.setHeader('Content-Type', 'application/json');
res.end(
JSON.stringify({
value: temp_actual
})
);
} catch (error) {
console.error(error.message);
};
});
}).on("error", (error) => {
console.error(error.message);
});
}
});
}
});
});
i really need to return/send/respond the temperature data to my front end but i'm getting said error, is there a different way to return data?
It looks like you are mixing up an HTTP server you wrote in Node (although you haven't shown any relevant code) and an HTTP client you also wrote in Node.
res is an argument received by the callback you pass to http.get and contains data about the response received by your HTTP client.
Meanwhile, somewhere else (not shown) you have a different variable also called res which is the object your HTTP server uses to send its response to the browser running your React code.
You are calling res.send and wanting res to be the latter but it is really the former.
Since you haven't shown us the HTTP server code, it is hard to say where that res is, but there is a good chance you have shadowed it and can solve your problem by using different names (e.g. client_res and server_res).
That said. I strongly recommend avoiding using the http module directly as the API follows out of date design patterns and isn't very friendly. Consider using fetch or axios for making HTTP requests and Express.js for writing HTTP servers.

NodeJs app "hanging" or "freezing" whenever an error occurs

When I make multiple post requests to my nodejs server and all of the parameters are correct, everything works fine (and doesnt freeze) but when I make multiple post requests with incorrect parameters that gives an error, my nodejs server just freezes/hangs for a few minutes. Why is this?
Here is my code btw
app.post('/pushtransaction', function(req, res) {
console.log(req.body);
console.log(5);
if (req.body.sigs) {
let sigver = xmf.modules.ecc.Signature.from(req.body.sigs).toString();
let lasig = [sigver];
console.log(req.body.packedTr);
let transi = JSON.parse(req.body.packedTr);
//let sigver = req.body.sigs;
let package = {
compression: 'none',
transaction: transi,
signatures: lasig
}
console.log(package);
//Pushes tx in correct format
xmf.pushTransaction(package).then(result=>{
res.send(result);
res.end();
console.log(result);
}).catch(err => {
console.log(err)
});
}
})
When your error is encountered, your Node server does not know what to do other than console.log() the error. It needs to end that request and send some response. You can res.status(400).send({ error: err }) when you're within the catch.
Make sure res.send() method gets called every time in your request.
Updated Javascript:
app.post('/pushtransaction', function(req, res) {
console.log(req.body);
console.log(5);
if (req.body.sigs) {
let sigver = xmf.modules.ecc.Signature.from(req.body.sigs).toString();
let lasig = [sigver];
console.log(req.body.packedTr);
let transi = JSON.parse(req.body.packedTr);
//let sigver = req.body.sigs;
let package = {
compression: 'none',
transaction: transi,
signatures: lasig
}
console.log(package);
//Pushes tx in correct format
xmf.pushTransaction(package).then(result=>{
res.send(result);
res.end();
console.log(result);
}).catch(err => {
console.log(err);
res.status(400).send();
});
}
res.status(400).send();
})
Additionally you don't have to call res.end() if you call res.send(). see Must res.end() be called in express with node.js?
Adding to other answers, you can add a middleware for timeouts, if any service fails to respond in some time, like
var timeout = require('connect-timeout');
app.use(timeout('5s'));

Fill an array based on a get response express

I have the following server.js get route
app.get('/', function(req, res) {
var url;
var final_res = [];
endpoints.forEach(function(url){
request(url, function(error,response,body){
if(!error && response.statusCode == 200){
final_res.push(url.url);
console.log(url.url);
}else{
res.send(err);
console.log(err);
}
});
});
});
And this is my client js where I fetch this exact same get with jQuery
$(document).ready(function() {
$.get('http://localhost:3000/', function(data) {
console.log(data);
$("#body").text(data);
});
});
When I open my index.html it displays the user interface correctly and inside my terminal where I have executing my server.js it correctly displays the url. What I can't accomplish is how to use my data that my jQuery receives in order to populate a table inside my html. My table will be populated with urls that are fetch from my endpoints.
I have some background in nodejs but I cant wrap this up.
Since you need to know when multiple requests are done, I'd suggest you switch to using the request-promise library so you can use promises to track when all the requests are done. That library also checks the statusCode for you automatically. So, you can do this:
const rp = require('request-promise');
app.get('/', function(req, res) {
Promise.all(endpoints.map(url => {
return rp(url).then(r => {
return url.url;
}).catch(err => {
// rather than error, just return null result
return null;
})
})).then(results => {
// filter out null values, then send array as the response
res.json(results.filter(item => item !== null));
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
});
This will run all the requests in parallel, but collect the results in order which should result in the fastest overall run time.
If you wanted to run them one a time, you could use async/await like this:
const rp = require('request-promise');
app.get('/', async function(req, res) {
let results = [];
for (let url of endpoints) {
try {
let r = await rp(url);
if (r) {
results.push(url.url);
}
} catch(e) {
// ignore error
}
}
res.json(results);
});
EDIT Jan, 2020 - request() module in maintenance mode
FYI, the request module and its derivatives like request-promise are now in maintenance mode and will not be actively developed to add new features. You can read more about the reasoning here. There is a list of alternatives in this table with some discussion of each one. I have been using got() myself and it's built from the beginning to use promises and is simple to use.
You must wait for all requests gets resolved to then send final_res array back to client. You can do this using async/await and Promise.all concepts. If you don't want to use these resources then you'll need to count and wait all request manually, using a counter to know when all requests has done, as below:
app.get('/', function(req, res) {
var url;
var final_res = [];
var respCounter = endpoints.length;
endpoints.forEach(function(url){
request(url, function(error,response,body){
respCounter--;
if(!error && response.statusCode == 200){
final_res.push(url.url);
console.log(url.url);
}else{
res.send(err);
console.log(err);
}
if(respCounter == 0) {
res.send(final_res);
}
});
});
});

Trouble with callbacks, error catching and MongoDB

I've been working on an application which allows me to add companies to a database. Originally my code was pure spaghetti, so I wanted to modularize it properly. For this purpose, I added routes, a controller and a dao.
This is how my code looks right now
Routes
app.post('/loadcompanies', (req, res)=> {
companiesController.loadcompany(req.body, (results)=>{
console.log(results);
res.send(200, "working!");
})
})
Controller
module.exports.loadCompany = (body, callback)=>{
companiesDao.loadCompany(body, callback);
}
Dao
module.exports.loadCompany = (company, callback)=>{
MongoClient.connect(conexionString, (err, database) => {
if (err) console.log(err);
db = database;
console.log(company);
db.collection('companies').insert(company, (err, result)=>{
callback({message:"Succesfully loaded company", company:result});
});
})
}
My current concern is that working with errors when modularizing like this is confusing. I tried adding a try-catch method around the db insert and throwing and error if there is one, but that doesn't seem to work. Other things I've tried is returning the error in the callback, like this:
if (err) callback (err, null);
but I end up getting a "Can't set headers after they are sent." error.
How would you handle errors in this situation? For example, in the case that someone tries to add a duplicate entry in an unique element.
You should be able to simply do the error checking inside the callback for the insert function:
db.collection('companies').insert(company, (err, result)=>{
if (err) {
callback(err, null);
return;
}
callback(null, {message:"Succesfully loaded company", company:result});
});
If you get an error like you say, that's probably because the database is actually returning an error. You could also make your errors more specific, like:
module.exports.loadCompany = (company, callback)=>{
MongoClient.connect(conexionString, (err, database) => {
if (err) {
callback(new Error('Connection error: ' + err.Error());
return;
}
db = database;
console.log(company);
db.collection('companies').insert(company, (err, result)=>{
if (err) {
callback(new Error('Insertion error: ' + err.Error());
return;
}
callback(null, {message:"Succesfully loaded company", company:result});
});
})
Here is your loadCompany done in async / await format.
Notise there is no need for error checking, errors will propagate as expected up the promise chain.
Note I've also changed loadCompany to be an async function too, so to call it you can simply do var ret = await loadCompany(conpanyInfo)
module.exports.loadCompany = async (company)=>{
let db = await MongoClient.connect(conexionString);
console.log(company);
let result = await db.collection('companies').insert(company);
return {message:"Succesfully loaded company", company:result};
}

Done function never called after $.ajax

I'm a bit new to all this (including Javascript callbacks and ES6). I'm using NodeJS + Express + MongoDB.
I'm calling an Ajax function to update an item and the success Ajax call is never done.
Here is my Ajax call (called from React)
editBug : function(bug){
console.log('about to edit bug with these values',bug);
$.ajax({
url:'/api/bugs',
method: 'PUT',
data:bug
})
.done((jqxhr) => {
console.log('succcess while editing the bug');
this.setState({successVisible : true});
})
.fail((jqxhr) => {
console.log('error : ' + jqxhr);
})
},
Here is my API function:
app.put('/api/bugs',function(req,res){
//console.log('req',req);
console.log('query string : ',req.query);
console.log('query params : ',req.params);
console.log('query body: ',req.body);
let id = new ObjectID(req.body._id);
req.body._id = new ObjectID(req.body._id);
db.collection('bugs').replaceOne(
{_id:id},
req.body,
function(err,result){
assert.equal(err,null);
console.log('Successfull replace!');
res.status(200);
}
);
});
The Successfull replace! log is correctly shown on the server side.
The about to edit bug with these values is correctly shown on the front side. But the succcess while editing the bug log is not shown on front end and it seems .done call is never executed.
The problem is that you are not sending any response back to the browser on node side. Try the following snippet and you should be good to go
Also, I'd like to point out that you should handle the errors. While updating the bugs if something goes wrong, the best practice would be to inform the browser with the 500 status code indicating that the intended action failed. I've added this aspect in the snipped below
app.put('/api/bugs', function(req, res) {
//console.log('req',req);
console.log('query string : ', req.query);
console.log('query params : ', req.params);
console.log('query body: ', req.body);
let id = new ObjectID(req.body._id);
req.body._id = new ObjectID(req.body._id);
db.collection('bugs').replaceOne({
_id: id
},
req.body,
function(err, result) {
if (err) {
console.log('Failed replace');
res.status(500).end(); // <- We set the response status code and end the request
} else {
assert.equal(err, null);
console.log('Successfull replace!');
res.status(200).end(); // <- We set the response status code and end the request
}
}
);
});
Don't you need to end your response object on the Node.js side?
Try adding res.end(); or any kind of response to your response object.
Also, you can use chrome's (or any other browser's) network tab to actually see how your AJAX requests end up, to see if they hang or finish.

Categories

Resources