Node.js Express response is ended before Promise resolve - javascript

Executing following code on Node.js with Express, but it does not return anything. It looks like res.send does not work from within promise.then(); Looks like it already returned back to the caller before promise resolve(); What I'm doing wrong? According to examples, it should work. Thanks.
const express = require('express');
const app = express();
app.get('/test', (req, res, next) => {
res.send("Good"); // Works Just Fine , but I dont need to return here
getMessage().then(function(data){
console.log("I'm here"); // Message works
res.send("Good"); // Does not Work
}).catch(function(error){
res.send("Error");
});
});
function getMessage(){
return new Promise(function(resolve, reject){
setTimeout(function() {
resolve();
}, 3000);
});
}
app.listen(PORT, () => {
console.log("run");
});

Please add following code to your app: Refer Here
This app starts a server and listens on port 8080 for connections
app.listen(8080, function () {
console.log('Example app listening on port 8080!')
})

You need to listen on a port for the express server to run.
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.get('/test', (req, res, next) => {
getMessage().then(function(data){
res.send("Good");
}).catch(function(error){
res.send("Error");
});
});
function getMessage() {
return new Promise((resolve, reject) => {
setTimeout(function() {
resolve();
}, 3000);
});
}
app.listen(port, () => console.log(`App listening at http://localhost:${port}`));

The problem was in request timeout setting in Postman that I'm using for testing.

Remove the first
res.send('good');
or you could res.write() first
then the message should be concatenated when res.send()
res.write('good')
res.send() closes the connection between the server and client
therefore using res.write() will write the message and when res.send() is sent all the written messages (using res.write()) are sent back to the client called
IN SHORT
res.write() can happen several times
res.send() happens once only per request

Related

Showing MQTT response on a node server API

I'm trying to output the response I receive from MQTT to a node serve setup using express.
There will be a json string message received from the mqtt service at every second.
The response would be output on /main API, which I would call from a Ionic 4 mobile app I'm working on.
However, now I can't display the data on the server itself just to check, I haven't thought of how I would constantly update the data as well on the server. The page doesn't refresh it just keeps loading.
const mqtt = require('mqtt')
const express = require('express')
const PORT = 8000
const app = express()
var client = mqtt.connect("mqtt://bac.com")
client.on('connect', () => {
console.log("Connected")
client.subscribe('/test')
})
app.get("/", (req, res) => {
res.send("ROOT");
});
app.get("/main", (req, res) => {
client.on('message', (topic, message) => {
res.send(message)
})
});
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
You would need to store your data somehow on the server side for your approach to work.
Implement some kind of storage service that stores the messages. Your client will need to respond to the queue messages and push these to storage, your api action will retrieve them from the storage, not from the queue.
const mqtt = require('mqtt');
const express = require('express');
const PORT = 8000;
const app = express();
const storageService = require("SOME KIND OF STORAGE SERVICE");
var client = mqtt.connect("mqtt://bac.com");
client.on('connect', () => {
console.log("Connected")
client.subscribe('/test')
});
client.on('message', (topic, message) => {
storageService.save(topic, message); //or this has to provide storage and enterpretation of the data comming in
});
app.get("/", (req, res) => {
res.send("ROOT");
});
app.get("/main", (req, res) => {
res.send(storageService.getAll());
});
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
You could also revisit the entire implementation, and push messages to the frontend via a socket or some other kind of persistant connection.
I have found a workaround from a similar question here. On the server side it will send data on message received. On the client side, it is an ajax call for every second to retrieve the data on the server side.
As described in the link, it really is a bad pattern. However, this would be suitable for those who have constraints to making changes to the MQTT service.
// Server.js
const mqtt = require('mqtt')
const express = require('express')
const PORT = 8000
const app = express()
var client = mqtt.connect("mqtt://bac.com")
var mqttMessage
client.on('connect', () => {
console.log("Connected")
client.subscribe('/test')
})
client.on('message', (topic, message) => {
console.log('Topic: ' + topic + '\nMessage: ' + message)
mqttMessage = message
})
app.get("/", (req, res) => {
res.sendFile("__dirname + "/index.html");
});
app.get("/main", (req, res) => {
if(mqttMessage)
res.send(mqttMessage);
else
res.status(404).send();
});
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
and on the index.html page:
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
$(document).ready(
function () {
setInterval(function () {
$.get('/main', function (res) {
$('#data').text(res);
});
}, 1000);
}
);
</script>
<p id="data"></p>
</body>

How to send ws message from route request

I've been trying to create an app that uses telegram-bot, express server and react app. Therefore, I need to create a POST request from telegram-bot to express, while express sends POST data to a websocket connection:
const express = require("express");
const app = express();
const expressWs = require("express-ws")(app);
// handles bot request
app.post("/request", (req, res) => {
playlist.push(req.body.url);
res.status(200).send({ message: "video is added to playlist" });
});
// after handling requst data must go here and send ws message to client side
app.ws("/echo", (ws, req) => {
ws.on("message", msg => {
ws.send(`msg is = ${msg}`);
});
});
Am I making it right, and if so, how to call ws.send from after handling request at app.post route?
From the understanding I have from your question, here is an updated version of your code that does exactly what you want.
I replaced the express-ws package with ws since that would be sufficient for your use case.
The express server runs on port 8080 while the websocket server runs on port 8081 since are different protocols and would not run on the same port (You can make it work but I do not recommend it See this question
const express = require("express");
const Websocket = require('ws');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
const wss = new Websocket.Server({ port: 8081 });
wss.on('connection', (ws) => {
console.log('One client connected');
ws.on("message", msg => {
ws.send(`msg is = ${msg}`);
});
})
// handles bot request
app.post("/request", (req, res) => {
// Broadcast URL to connected ws clients
wss.clients.forEach((client) => {
// Check that connect are open and still alive to avoid socket error
if (client.readyState === Websocket.OPEN) {
client.send(url);
}
});
res.status(200).send({ message: "video is added to playlist" });
});
app.listen(8080, () => {
console.log('Express listening on 8080');
console.log('Websocket on 8081');
});
Tested via curl with curl -d 'url=https://example.com/examplesong' localhost:8080/request I had a client connected to ws://localhost:8081 and everything looks good.

Temporary 'loading' route in Express?

I have a web app that takes a moment to load - as it needs to connect to a database, and so some other things that take time.
What's the best way to have a temporary loading route in Express?
I'd like to do something like the following:
const express = require('express')
const app = express()
// Temporary / for if someone hits the server before it's finished starting
app.get('/', (req, res) => res.send(`Loading....`))
// In my non-demo app, there's a router here that takes a moment to load, instead of a timeout.
setTimeout(function(){
app.get('/', (req, res) => res.send(`Ready!`))
}, 3 * 1000)
app.listen(3000, () => console.log('Example app listening on port 3000!'))
Routes can't be deleted at runtime, but you can add a middleware that checks if everything is initialized, if it isn't you end the request with: res.send('Loading'); otherwise you go to the next middelware.
let initialized = false;
app.get('/', (req, res, next) => {
if(!initialized)
return res.send('Loading...');
next();
});
app.get('/', (req, res, next) => {
res.send(`Ready!`);
});
setTimeout(() => initialized = true, 3000);
If your app needs some time to load properly, the best option is to NOT let it start the server.
It works very well with i.e. load balancers and multiple containers as they wait for the /health check to pass before they put the container behind the loadbalancer. Which is something you want to do for modern services.
For example this:
import { app } from './app';
import { config } from './config';
import { logger } from './components/ourLog';
import { initPromise } from './components/ourMongo';
const port = config.server.port;
async function startServer() {
await initPromise;
app.listen(port, () => {
logger.info(
{
port,
params: config.params,
processEnv: process.env,
},
'App has started'
);
});
}
startServer()
.catch(err => {
logger.error({ err }, 'Critical error, cannot start server');
process.exit(1);
});
We have component that connects to mongo and it expose initPromise, which is the promise, which is resolved after the connection is sucesfully done and you can start with using the db.
You could ping the server "x" seconds to test when it is ready.
Server
We will create a ready variable, that is set to false, when all of your database, api and other things are done doing what they need you set it to true.
We will also create a route that such as /ping that will respond with the value of ready.
const express = require('express')
const app = express()
let ready = false
// Do database stuff, API stuff, etc.
// Set ready to true when ready
// Temporary / for if someone hits the server before it's finished starting
app.get('/', (req, res) => res.send(`Loading....`))
app.get('/ping', (req, res) => res.json({ready}))
app.listen(3000, () => console.log('Example app listening on port 3000!'))
Client
Here we will ping the server every "x" seconds, I set it to 0.5s, once ping returns true, we cancel the timeout and run the initialization code that builds the page.
let timeout
timeout = setInterval(async () => {
let response = await fetch('/ping')
let ready = await response.json()
if (ready.ready) {
clearInterval(timeout)
loadpage()
}
}, 500)

Opening and closing DB connection during API call [duplicate]

This question already has answers here:
Why is it recommended not to close a MongoDB connection anywhere in Node.js code?
(4 answers)
MongoDB - open and close connection - advise for good practice
(1 answer)
Closed 5 years ago.
My app.js looks below. mogoDBUtils.getMogoDbCon(); will open a db connection when new request comes in. I want to close the DB connection as soon as the api call to route.js is over.
Where do i need to place the code in app.js to close MongoDB connection in the below code so that upon evey new hit it opens a connection and close the connection after api call is completed.
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.disable('x-powered-by')
var mogoDBUtils = require('./controller/utilities/mongodbutils.js')
var logger = require('./controller/utilities/logger.js'); //initialize logger class
require('./routes/route.js')(app); //define express router for api calls
mogoDBUtils.getMogoDbCon(); //open dbconnection
//setup server
var port = process.env.PORT || 80 // port
app.use(express.static('./views/webcontent/', { index: 'index.html' }))//define home page
app.listen(port);
console.log('Listening on port ' + port + '..');
// DB functions
module.exports.getMogoDbCon = function() {
new Promise((resolve, reject) => {
var mongoUri = getmongouri();
mongoose.connection.openUri(mongoUri);
var db = mongoose.connection;
db.on('error', function () {
throw new Error('unable to connect to database');
});
return resolve(db);
});
};
module.exports.closeMongoDBConnection = function () {
new Promise((resolve, reject) => {
mongoose.disconnect();
return resolve(true);
});
};
You can do it in a middleware. If you want to open and close connection on each request, you need to create two middlewares: for opening connection and for closing it:
I suppose that getMogoDbCon() and closeMogoDbCon return a promise, otherwise use callbacks.
app.use((req, res, next) => {
mogoDBUtils
.getMogoDbCon()
.then(conn => {
req.conn = conn;
next();
})
.catch(next);
});
require('./routes/route.js')(app); // define express router for api calls
app.use((req, res, next) => {
mogoDBUtils
.closeMogoDbCon(req.conn)
.then((() => next())
.catch(next);
});
Note about middleware order declaration. The middleware which opens connection must be defined firstly, after that all your routes, and the last one - the middleware which closes connection.

Calling methods from other files with Node.js

I'm failing to require methods from my ./db/index.js into my server.js file to select data from the database and display it.
The /db/index.js is like this:
'use strict';
const pgp = require('pg-promise')();
const pg = pgp(process.env.DATABASE_URL);
let select = () => {
pg.any('SELECT username, status FROM status')
.then(function(data){
for (var item of data) {
return item.username + "'s status is " + item.status;
}
})
.catch(function(err) {
return 'Error: ' + err.message || err;
});
};
module.exports = () => {
select
};
and I want to call it in from a different file:
'use strict';
const port = process.env.PORT || 3000;
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const db = require('./db/');
app.use(bodyParser.urlencoded({extended: true}));
app.post('/logdash', function(req, res, next) {
res.status(200).send(db.select());
});
app.listen(port, function() {
console.log('Server is running on port', port);
});
I'm using Heroku, and like this, watching the logs, no error is shown in both terminal and Slack (it's a slash command). I can't find help on how to properly separate the functions. How can I call this select method and any other one from a different file?
There are many problems in your code, some of them listed in the previous answer by #jfriend00.
I will only add that you also do not return any data from the method when it is successful.
Considering how many errors you got there, rather than re-iterating them, I will give you a corrected code example instead.
The database module:
'use strict';
const pgp = require('pg-promise')();
const db = pgp(process.env.DATABASE_URL);
let select = (req, res, next) =>
db.map('SELECT username, status FROM status', null, row=> {
return row.username + "'s status is " + row.status;
})
.then(data=> {
res.status(200).send(data);
})
.catch(err=> {
res.status(500).send(err.message || err);
});
module.exports = {
select
};
And the HTTP service file:
'use strict';
const port = process.env.PORT || 3000;
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const db = require('./db/');
app.use(bodyParser.urlencoded({extended: true}));
app.post('/logdash', db.select);
app.listen(port, function () {
console.log('Server is running on port', port);
});
The code is based on pg-promise v.4.3.x (upgrade, if you have an older one).
I wouldn't say it is a good approach to organizing your code, but at least it is a working example. You can check out pg-promise-demo for a complete application example that may give you a better idea of how to organize your database code.
API references: map
The code in your module is asynchronous. You can't return a value directly. Instead, you should return the promise and then use the promise from the caller to obtain the final asynchronous value.
For further discussion of this general concept see this answer:
How do I return the response from an asynchronous call?
Change your code to this (see embedded comments):
'use strict';
const pgp = require('pg-promise')();
const pg = pgp(process.env.DATABASE_URL);
let select = () => {
// return the promise here
return pg.any('SELECT username, status FROM status')
.then(function(data){
return data.map(function(item) {
return item.username + "'s status is " + item.status;
});
})
.catch(function(err) {
// to keep this an error, we have to rethrow the error, otherwise
// the rejection is considered "handled" and is not an error
throw 'Error: ' + err.message || err;
});
};
// export the function
module.exports.select = select;
And call it like this:
'use strict';
const port = process.env.PORT || 3000;
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const db = require('./db/');
app.use(bodyParser.urlencoded({extended: true}));
app.post('/logdash', function(req, res, next) {
db.select().then(function(data) {
res.status(200).json(data);
}).catch(function(err) {
// add some sort of error response here
res.status(500).json(err);
});
});
app.listen(port, function() {
console.log('Server is running on port', port);
});
Summary of changes here:
In select(), return the promise
In the .catch() in select(), rethrow the error to keep it a rejected promise. If you add a handler for a .catch() and don't either rethrow or return a rejected promise, then the error is handled and the promise becomes resolved.
You need to fix your for loop. It should not be doing a return inside the for loop with no conditional checks. That code is probably just wrong (though I'm not sure what you intended to do).
When you call db.select(), use a .then() handler to get teh final resolved value.
Add an error handler for the db.select() promise.
Change the exports so that db.select() is your function.
Revised the way you were referencing data in the for loop so it will actually fetch the desired property.
A few things. I would make sure that your select function returns a Promise. I would also handle the promise in your route. This way you can properly send the appropriate status codes and responses.
db/index.js
'use strict';
const pgp = require('pg-promise')();
const pg = pgp(process.env.DATABASE_URL);
let select = () => {
return pg.any('SELECT username, status FROM status')
}
module.exports = () => {
select
};
server.js
'use strict';
const port = process.env.PORT || 3000;
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const db = require('./db/');
app.use(bodyParser.urlencoded({extended: true}));
app.post('/logdash', function(req, res, next) {
db.select()
.then((data) => {
res.status(200).json(data)
})
.catch((error) => {
res.status(500).json(error)
})
});
app.listen(port, function() {
console.log('Server is running on port', port);
});
I did not test this, but it should do the trick.

Categories