Express.js/Node.js Responses Before Query Finishes - node.js

I have a local server that is fully functioning when POSTs and GETs are sent from Postman or chrome rest apps etc. However, whenever I send it from an ESP8266 it fails as it follows:
This is my server side code:
router.get('/', function (req, res) {
var person = req.query.id;
console.log("1");
Person.find({person: personID} ,function (err, station) {
if(err) console.log(err.message);
console.log("3");
res.send('test');
console.log("4");
});
console.log("2");
});
Lines below are from console when request is sent from Chrome.
1
2
3
4
GET /api?id=ABKWTltz6Ug 200 21.829 ms - -
And the lines below are from console when request is sent from ESP8266.
1
2
GET /api?id=ABKWTltz6Ug - - ms - -
3
4
As you may notice logs 3 and 4 are after GET response line. My ESP8266 TCP connection lines match the HTTP Message Format:
GET /api HTTP/1.1
Host: *SERVER_IP_ADDRESS*
The problem raised when we switched from PHP to NodeJS backend server. ESP8266 used to connect and operate without problems back then. And FYI, everything also works fine if I remove the Person.find code block and move the res.send('test'); outside.
Another freshly written backend code to hopefully spot the error is below. This is the whole code. Which also returns the same error I've mentioned earlier above:
var express = require('express');
var app = express();
var router = express.Router();
var mongoose = require('mongoose');
var morgan = require('morgan');
app.use(morgan('dev'));
mongoose.connect('mongodb://localhost/test');
//mongoose.Promise = Promise;
var Test = mongoose.model('Test', { name: String });
router.get('/test', function (req, res) {
console.log("1");
var test1 = new Test({
name: "Name"
});
var query = test1.save();
query.then(function (doc) {
res.send('1').end();
console.log('3');
});
console.log("2");
});
app.use('/api', router);
var port = 9000;
app.listen(port,function(){
console.log('server started on', port);
});

Related

Node js(Express framework): not able to print number API from external server to client browser

I am trying to retrieve weather API from external server and when I am console logging particular data of weather API, it's also showing on my command prompt.
But when I am using get method to show that data on browser I am only able send string data like "description": moderate rain and not number data like "temp": 27
it the crash the app.
Node js code:
//jshint esversion:6
const express = require("express");
const app = express();
const https = require("https");
app.get("/", function(req, res) {
const url = "https://api.openweathermap.org/data/2.5/weather?q=mumbai&appid=d88391210768983e6be06cdd76bdcde3&units=metric";
https.get(url, function(response) {
console.log(response.statusCode);
response.on("data", function(data) {
const weatherData = JSON.parse(data);
const temp= weatherData.main.temp;
const description= weatherData.weather[0].description;
console.log(temp);
console.log(description);
res.send(temp);
});
});
});
app.listen(3000, function() {
console.log("Server is running on port: 3000");
});
You should ideally return a json.
It can be:
res.send({temp: temp, description: description});
The res.send has to return a string/object/array/buffer.
You could do something like:
res.status(200).send(temp)
But sending json response is preferable, and you can scale it as well.
Another hack kind of solution is:
res.send("" + temp)

is this the correct way to send data received from twitter api to the browser using nodejs?

I am still learning nodejs and was listening to daniel shiffman's video on how to setup the twitter api and how to get data from it.
Now, the code was working and I was getting back data, but it was all happening in the terminal.
What I wanted to do was to show the twitter data in my browser and wasnt sure how to do that. I tried searching for it, but didnt get much help.
So, I just tried doing whatever I knew and it worked and therefore I am still not sure that the code I have written is the proper way to do this.
I'd love to know if there's a mistake somewhere or If there's some other way I should have done this.
Anyways, here's the code
var http = require('http');
var express = require('express');
var app = express();
var port = 8080; // Use 8080 for local development because you might already have apache running on 80
console.log('The bot is starting');
var Twit = require('twit');
var config = require('./config');
console.log(config);
var T = new Twit(config);
var params ={
q:'spider',
count:5
}
T.get('search/tweets', params, gotData);
function gotData(err, data, response) {
var tweets = data.statuses;
app.get('/',function(req,res){
req=params;
var tweetz='';
for(var i=0;i<tweets.length;i++){
console.log(tweets[i].text+'================================');
tweetz = '<p>'+ tweetz+tweets[i].text+'</p>';
}
res.send(tweetz);
});
}
app.listen(port, function () {
console.log(`app listening on port ${port}!`);
});
The mistake you are doing is declaring app.get inside the callback.
app.get("/", function....) is a route which responds to GET requests which means whenever a user requests for "/", the callback which is the function(req, res) is called.
So the code should be:
app.get("/", function(req, res) {
// User requested for "/" route, now get tweets
T.get('search/tweets', params, function(err, data) {
//Tweets received, now send the tweets to the user
var tweets = data.statuses;
return res.send(tweets);
})
})
Then go to http://localhost:8080/ and it should work.

Node js - how to handle multiple asynchronous tasks

I'm new to node and got stuck with handling multiple async tasks.
Except from node, I've got another server (S1) which doesn't return data immediately to requests, it can returns multiple types of data and also can send notifications without requesting them specifically, so node have to listen to data from it , parse it and act accordingly.
The connection to this server (S1) is done by using:
S1 = net.createConnection({'host':S1Host, 'port': S1Port});
And node listens to data with:
S1.on('data', function(data){
S1DataParse(data);
});
I have to route the correct data (after parsing it) to a specific POST request.
app.post('/GetFooFromS1', function(req, res){
// Send request to S1
S1.write({'type':'foo'});
// If got the correct data sometime in the future, send response to the browser
res.setHeader('Content-Type', 'application/json');
res.json({'status':'success', 'value':S1FooData});
});
I tried to use the async module for that, but with no success.
What I was trying to do:
var asyncTasks = [];
app.post('/GetFooFromS1', function(req, res){
asyncTasks.push(function(callback){
// Send request to S1
S1.write({'type':'foo'});
});
async.parallel(asyncTasks, function(response){
res.setHeader('Content-Type', 'application/json');
res.json({'status':'success', 'value':response});
});
});
and another task in S1DataParse:
function S1DataParse(){
if(data.type='foo'){
asyncTasks.push(function(callback){
callback(data);
});
}
}
But, of course, the second task never added to the asyncTasks array. I really got stuck with that.
Can you please help me with that?
Thanks
-=-=-=- Edit -=-=-=-
Eventually, I came accross with events and EventEmitter().
From the POST request I call the function that sends requests to the data server (DataServerClientGet).
In this function I register a listener which will get the future data.
eventEmitter.on('getData', returnDataServerData);
It all works great except for one thing. Whenever I refresh the page or add other POST requests, I get an error:
Error: Can't set headers after they are sent.
It would be great if I solve this problem. Help me, please.
Thanks ;)
The whole code looks like this:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var bodyParser = require('body-parser')
var net = require('net');
var events = require('events');
var dataServerHost = '127.0.0.1';
var dataServerPort = 12345;
var dataServerClient;
var logMsg;
var eventEmitter = new events.EventEmitter();
/*******************************************/
// Init
/*******************************************/
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.static(__dirname + '/public'));
/*******************************************/
// Connect to the data server
/*******************************************/
DataServerConnect();
/*******************************************/
// Open listener on port 3000 (to browser)
/*******************************************/
http.listen(3000, function(){
logMsg = 'listening on *:3000';
console.log(logMsg);
});
/*******************************************/
// Routing
/*******************************************/
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
app.post('/GetDataFoo', function(req, res){
var msg;
var size;
msg ='\n{"Type":"Query", "SubType":"GetDataFoo","SearchFilter":""}';
size = msg.length;
logMsg = 'Client to DataServer: GetDataFoo';
console.log(logMsg);
DataServerClientGet('GetDataFoo', size, msg, res);
});
/*******************************************/
// Functions
/*******************************************/
function DataServerConnect(){
dataServerClient = net.createConnection({'host':dataServerHost, 'port': dataServerPort}, function(){
logMsg = 'Connected to DataServer ['+dataServerHost+':'+dataServerPort+']';
console.log(logMsg);
});
dataServerClient.on('data', function(data){
logMsg = 'DataServerData>>>\n'+data.toString()+'DataServerData<<<';
console.log(logMsg);
DataServerDataParse(data.toString());
});
dataServerClient.on('end', function(){
logMsg = 'Disconnected from DataServer';
console.log(logMsg);
});
}
function DataServerClientGet(type, size, msg, res){
dataServerClient.write('Type: Json\nSize: '+size+'\n\n'+msg, function(err){
var returnDataServerData = function returnDataServerData(results){
res.setHeader('Content-Type', 'application/json');
res.json({'status':'success', 'value':results});
}
eventEmitter.on('getData', returnDataServerData);
}
function DataServerDataParse(json){
if(json.Type=='GetDataFoo')
{
var MessageList = json.MessageList;
eventEmitter.emit('getData', MessageList);
}
}
-=-=-=- Edit -=-=-=-
The Error: Can't set headers after they are sent. caused by adding the same listener of the same type each time the DataServerClientGet was called and the res was sending multiple times.
I solved this one by adding: removeListener(event, listener)
right after the res, inside the function. Anyway, I think it's wrong and can cause problems if there will be multiple calling to DataServerClientGet with the same type etc.
There is a optional callback parameter that you can pass to write function(docs), something like :
S1.write({'type':'foo'},function(err){
if(err){
//Handle error
}else{
res.setHeader('Content-Type', 'application/json');
res.json({'status':'success', 'value':response});
}
})
This can work with post route , but in your 'data' listener ,you cant send data from server to client when there is not connection initialized by client (it is not bidireccional ) if you want bidireccional behavior you can check socket.io

expressjs - piping to response stream doesn't work

I have this basic express app:
var express = require('express');
var app = express();
var PORT = 3000;
var through = require('through');
function write(buf) {
console.log('writing...');
this.queue('okkkk');
}
function end() {
this.queue(null);
}
var str = through(write, end);
/* routes */
app.get('/', function(req, res){
res.send("Hello!");
})
app.post('/stream', function(req, res){
var s = req.pipe(str).pipe(res);
s.on('finish', function() {
console.log('all writes are now complete.'); // printed the first time
});
});
/* listen */
app.listen(PORT, function () {
console.log('listening on port ' + PORT + '...');
});
When I post some data to /stream endpoint for the first time after starting the server I get okkk as the response which is what I expect. However, after that, any requests to /stream endpoint just timeout and not return any response.
Why is it so? What's exactly happening here?
I had this same problem and looks like res was not being finished properly. So I added a callback to my stream and ended que res myself. That fixed my problem:
stream.on('end', () => res.end());
stream.pipe(res);
It worked when I replaced req.pipe(str).pipe(res) with req.pipe(through(write, end)).pipe(res) which essentially makes sure that a new instance of through stream is created for every request.

node-amqp + rabbitMQ how to convert post request into message

I have express server setup to listen post request and put the post request in message queue
var express = require('express');
var app = express();
app.use(express.bodyParser());
app.post('/test-page', function(req, res) {
var amqp = require('amqp');
var connection = amqp.createConnection({url: "amqp://guest:guest#localhost:5672"},{defaultExchangeName: ''});
connection.on('ready',function(){
console.log('connected');
var messageToSend = req.body;
var queueToSendTo = "xyz";
connection.queue(queueToSendTo,{'passive': true},function(){
connection.publish(queueToSendTo, messageToSend);
res.send(200);
connection.end();
});
});
});
app.setMaxListeners(0);
app.listen(80);
The above code is suppose to collect the post request and put in queue, If I send 10 requests, there would be more than 300 messages in queue. I don't understand this behaviour or may be my understanding of putting 'publish' call in 'ready' function is wrong since the 'connected' log message in above code is printed more than 10 for 10 post request.
Is it happening due to 'connection.end' not closing the connection?
I want to have each post request converted to a message in RabbitMQ,
Please advise if there is any better way.
(I am using latest master of node-amqp with rabbit-server-3.1.4-1 on ubuntu 12.04)
The issue it's that you are creating a connection to the queue for every post request to test-page. So you have to create this connection outside of the post handler.
I haven't tested the code but this should do the trick:
var express = require('express');
var app = express();
app.use(express.bodyParser());
var amqp = require('amqp');
var connection = amqp.createConnection({url: "amqp://guest:guest#localhost:5672"},{defaultExchangeName: ''});
connection.on('ready', function() {
console.log('connected');
});
app.post('/test-page', function(req, res) {
var messageToSend = req.body;
var queueToSendTo = "xyz";
connection.publish(queueToSendTo, messageToSend);
res.send(200);
});
app.setMaxListeners(0);
app.listen(80);

Resources