NodeJS Middelware/Routing Data transfer - javascript

Hello i'm trying to transfer more data to the client. I have used sample code for the middleware in NodeJS express.
I want to read 2 different files and transfer the data to the client. I have managed to transfer 1 file data. How can I add multiple?
how should I do this?, I have tried 'send' and 'json' but then I cant see my front end of the website
var express = require('express');
var router = express.Router();
const fs = require('fs');
/* GET home page. */
// const myHtml = require('fs').readFileSync(<path to html>);
const myHtml = fs.readFileSync('./views/index.html', 'utf-8');
//Data from server to client, this works.
const myJson = fs.readFileSync("./apidata.json", 'utf-8');
//I want to add a second one here
const apisparkline = fs.readFileSync("./apisparkline.json", 'utf-8');
console.log("server is running");
router.get('/', function(req, res, next) {
//This works perfect
res.end(myHtml.replace(/jsonapidata/g, JSON.stringify(myJson, '', 2)));
//how should I do this?, I have tried 'send' and 'json' but then I cant see my front end of the website
res.end(myHtml.replace(/sparklinedata/g, JSON.stringify(apisparkline, '', 2)));
});
module.exports = router;

Simply use,
res.end(myHtml.replace(/jsonapidata/g, JSON.stringify({myJson,apisparkline}, null, 2)));
Better way,
res.json({myJson,apisparkline})
and then, format at client.

Related

Cannot get objects' values from request body while trying to POST [Node.js, MySQL]

I am working on a management system, currently creating the POST requests for the api. I need the values of the request's body to post a new city in the database. The values are used in the stored procedure as parameters. Instead of the key's values which I entered, I am getting an "undefined" value, sometimes a "[object Object]".
I am using a MySQL server, hosted in the cloud by Google's services. Backend is made with Node.js, routing with Express. None of my attempts to fix the bug worked for me.
What I've tried so far:
-Parsing each key's value .toString() and JSON.stingfify() from the body
-Converting the body to Json/string, then back to a javascript object
-Getting the response's requests's body (res.req.body)
-Getting the body's response values in an array, then pushing the next element after it has been passed as a parameter to the stored procedure
-Using the 'request' npm extension to put the values I need when calling the POST method.
-Changed the values to be stored in the URL' parameters instead of the body.
-Sent the body's values as form-data, JSON file, HTML page
Controller method in cityController.js:
exports.city_post = (req, res, next)=>{
poolDb.getConnection(function (err, connection){
if(!err) {
const sql = 'CALL createNewCity(?,?)';
var zipReq = req.params.zip;
var nameReq = req.params.name;
var reqBody = JSON.stringify(req.res.body);
connection.query(sql,[zipReq,nameReq], (err,rows)=>{
if(!err){
return res.status(201).json({Message: 'City with name: '+nameReq+' and zip code: '+zipReq+' created successfully\n', rows});
}
else{
return res.status(404).json({errorMessage: err})
}
});
}
else{
return res.status(500).json({errorMessage: "server error: "+this.err});
}
console.log("\nZip Code: "+ zipReq +"\nName: " + nameReq); //for testing
console.log("\nrequest body: " + reqBody); //for testing
});
}
City route:
const express = require('express');
const router = express.Router();
const CityController = require('../controllers/cityController.js');
router.get('/', CityController.city_getAll);
router.get('/:cityzip', CityController.city_getbyzip);
router.post('/add', CityController.city_post);
...
module.exports = router;
Expected: Posting a new field in table city, status code (201).
Actual: Status code (404), no new insertion in the DB. body, req.body.zip & req.body.name are of value "undefined".
Screenshots:
-Terminal output: https://imgur.com/a/brqKZlP
-Postman request: https://imgur.com/a/ZfFcX8Z
Express doesn't parse post body by default (for some reason). You can try popular body-parser npm package, or collect the raw body data and parse from a string yourself if you don't want to add a whole new package. Here as express app:
app.use(function(req, res, next){
var data = "";
req.on('data', function(chunk){ data += chunk})
req.on('end', function(){
req.rawBody = data;
var json = JSON.parse(req.rawBody); // assuming valid json. ideally check content-type first
next();
});
});

nodejs variable scope issue

I have a nodejs route where I am trying to download a url as mp3 using npm-youtube-dl. I have a download directory that I watch with chokidar for files being added and when a file is added I save the link to the file and after the download finishes I call a function that's supposed to respond with the download URL using res.download. When the sendURL function is called the url that I can clearly see has been saved before is undefined when I console.log it... Any idea what i'm doing wrong here/how I can fix this? i'm guessing it's a js variable scope issue?
my code:
var express = require('express');
var router = express.Router();
var yt = require('youtube-dl');
var fs = require('fs');
var path = require('path');
var chokidar = require('chokidar');
var downloadPath = '';
var watcher = chokidar.watch('./downloads', {
ignored: '/^[^.]+$|\.(?!(part)$)([^.]+$)/',
persistent: true
});
watcher.on('add', function(path) {
console.log('added: ', path);
this.downloadPath = path;
console.log('saved', this.downloadPath);
});
/*
router.get('/', function(req, res, next) {
next();
});
*/
router.get('/', function(req, res) {
var url = 'https://soundcloud.com/astral-flowers-music/bella-flor';
var options = ['-x', '--audio-format', 'mp3', '-o', './downloads/%(title)s.%(ext)s'];
var video = yt.exec(url, options, {}, function exec(err, output) {
if (err) { throw err; }
console.log(output.join('\n'));
sendUrl();
});
function sendUrl() {
console.log(this.downloadPath);
//res.download(this.downloadPath);
}
});
module.exports = router;
You're misusing this. If you want to use the downloadPath variable in your functions, remove the this. from in front of them. this.downloadPath looks for a property called downloadPath on an object referenced by this, which is different from your module-global variable.
More: How does the "this" keyword work?
Even with that, you're relying on your add callback having been called before any client requests your / route, and you're returning the last value assigned to downloadPath by that add callback. I don't know enough about what you're doing to know whether that's correct, but the lack of coordination seems problematic.

How to pass parameters between node.js and HTML?

I am a new user of node.js and mongodb and still learning. Please excuse if the question seems very simple. My node.js MongoDB query script (hello.js) is-
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var url = 'mongodb://localhost:27017/flood';
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
console.log("Connected correctly to server.");
var collec_name="99"
var field_name ="data1"
var value=311
db.collection(collec_name).find({data0:value}, {[field_name]:1, _id:0}).toArray(function(err, result) {
if (err) throw err;
console.log(result);
db.close();
});
});
The query runs fine with command- node hello.js and got the expected value result (for instance, output value of result is 0.000115). Note that var collec_name="99", var field_name ="data1" and var value=311 contain fixed values.
My HTML file (index.html) is-
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<script>
var c_n = "99";
var f = "data1";
var v = 311;
document.getElementById("demo").innerHTML = 0.000115;
</script>
</body>
</html>
Now, I want to pass the values of variable c_n, v and f from index.html to hello.js by replacing three statements of hello.js as-
var collec_name=c_n
var field_name = f
var value = v
Then, I want to pass value of result from hello.js to the index.html by replacing one statement of index.html as-
document.getElementById("demo").innerHTML = result;
So, how can I achieve these parameter passing so that if I run the index.html page, I can display the value of result on the web? Any solution script based on my scripts will be highly appreciated.
To send data between your back-end and your client you have to use AJAX, socket.io or WebSockets.
If you only have to update the back-end if the clients wants to you should use AJAX. If your client has to be notified by the back-end (Server), you should use socket.io or WebSockets for that.
Because you are using NodeJs, i would recommend you to use socket.io.
Just have a look at it:
https://socket.io/
Here a example for your code:
First install the package:
npm install -S socket.io
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
// add socket io
var app = require('http').createServer(handler)
var io = require('socket.io')(app);
// connect to port
app.listen(3030);
var url = 'mongodb://localhost:27017/flood';
// setup server
io.on('connection', function (socket) {
// add event
socket.on('data', function (data) {
// execute after event was emitted
MongoClient.connect(url, function (err, db) {
assert.equal(null, err);
console.log("Connected correctly to server.");
var collec_name = data.collec;
var field_name = data.field;
var value = data.value
db.collection(collec_name).find({ data0: value }, { [field_name]: 1, _id: 0 }).toArray(function (err, result) {
if (err) throw err;
// TODO add emmit
console.log(result);
db.close();
});
});
});
});
HTML:
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<script src="path/to/socket.io"></script>
<script>
var socket = io('http://localhost');
// send message
socket.emit('data', {
collec: "99",
field: "datal",
value: 311
});
// TODO add listener
document.getElementById("demo").innerHTML = 0.000115;
</script>
</body>
</html>
Finally, I was able to solve the problem. As I didn't find any perfect solution on net, I thought it will be helpful for other users (who are facing similar problem) if I post a general solution to a similar problem here. Please excuse if this is not the right place to post the solution.
My Solution: This is not the exact solution of my above example but I think it is better to provide a general solution to a similar problem so that anyone can always modify/update this solution according to his/her example/need as basic approach will be always same. At first, you need to have http, express and body-parser and you can do by following the commands:
npm install http
npm install express
npm install body-parser --save
A general problem: Suppose, I have two numbers (for instance a = 20 and b = 24 in the client HTML page and I want to sum up the numbers from the server side and get the summation result (sum = 44) back in the client side to display in the HTML page. Then use the following nodejs and ejs scripts-
index.ejs:
<html>
<head>
<title>Example solution</title>
<script src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
<script type="text/javascript">
$(function(){
$('#loadRequest').click(function(e) {
e.preventDefault();
console.log('Load_button clicked');
var data = {};
data.a = 20; //input
data.b = 24; //input
$.ajax({
type: 'POST',
data: JSON.stringify(data), //input data to be sent to the server
contentType: 'application/json',
url: 'http://localhost:80/endpoint',
success: function(res) {
console.log('success');
console.log(res);
$("#demo").html(res); //summation displayed in the HTML page
}
});
});
});
</script>
</head>
<body>
<p id ="demo"></p>
<button id="loadRequest">Load</button>
</body>
</html>
server.js:
var http = require('http');
var express = require('express');
var app = express();
app.set('view engine', 'ejs'); //tell Express we're using EJS
app.set('views', __dirname + '/views'); //set path to *.ejs files
app.use('/public', express.static(__dirname + '/public'));
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
app.get('/', function(req, res) {
//render index.ejs file
res.render('index');
});
app.post('/endpoint', function(req, res){
var x = req.body.a; //received input 1 from client side
var y = req.body.b; //received input 2 from client side
console.log(x);
console.log(y);
var sum =x+y;
console.log(sum);
res.send(String(sum)); //sending summation to the client
});
http.createServer(app).listen(80);
It worked perfectly. Please let me know if you have any comment/feedback.
You can either implement an API yourself using AJAX, WebSockets or socket.io - or you can go ahead and take a look into Express framework.
Setting up a Node.js server using Express will not only provide you access to a rich API interface, it would also make your task much easier.
Using it, you can set up a simple route like this:
app.post('/compute', function(req, res){
// compute 'result'
res.send(result);
});

Node.js: Using Socket.io in an express.js route to send message to a specific client

I have made a very casual commenting system, and now I want to add replies. So, when someone posts a reply on someone else's comment, that user must be notified that someone replied to their comment. In order to do that, when the replier clicks the reply button an AJAX post request is made to the server, the server then needs to get the id of the first commenter and send them a response text using socket.io (socket.io is not required to be used if there is another way to send the reply text with another module or express itself). This is my code so far:
app.post('/reply', function(req, res){
var commenterId = req.body.userId; // this is the id of the original commenter, not the replier
User.findOne({'_id':commenterId}, function(err, user){
user.send({'replied': req.user._id}); // this is what I need to do, and
//I don't know if this specific code works and that's why I'm asking if there is a way to do it with socket.io,
// io.to(socketId).emit('reply', 'some reply text here...'); // but if I do this I don't know how to get the socketId!
//Is there even a way to do this? Maybe with another module,
//or some express function I don't know about? And if it is done with express how would
//the client side code, look like? Thank you!
});
res.end();
});
//app.js file
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var routes = require('./routes/routes')(io);
app.use('/', routes);
//router file
var express = require('express');
var router = express.Router();
var _socket = null;
//list of socket users.once they logout delete the socket by
//delete users[_socket.userid];
var users = {};
var returnRouter = function(io) {
io.sockets.on('connection', function (socket) {
//now _Socket is available inside routes
_socket = socket;
});
router.post('/login', function(req, res) {
//authentication logic
User.findOne({'email': req.body.email}, function (err, user) {
//userid must be unique
_socket.userId= user.userId
//set session variable to store id of the user
req.session.userId = user.userId;
//now every user has a socket associated with their id
users[_socket.userId] = _socket;
});
});
router.post('/reply', function (req, res) {
var commenterId = req.body.userId;
User.findOne({'_id': commenterId}, function (err, user) {
// you can get the id of the logged in user that is the creator
//of the original post from req.session.userId
//if you have implemented session store
//the commenter user object is obtained from findOne method
users[req.session.userId].emit('notification', {
notification: user.username+' commented on your post'
}});
});
res.end();
});
return router;
};
module.exports = returnRouter;

combining functionality of two Node servers with different initial set up

I have two node servers and I need to combine them so one server has the functionality of both. They were set up a little differently and I'm not sure how to resolve it.
The first server has the require statements at the top, routes in the middle and creates the server at the bottom like this:
var express = require('express');
var routes = require('./routes');
etc..
// middleware
// routes
http.createServer(app, function(req, res){
// get files
// check for errors
}).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
The second one looks like this:
var express = require('express')
, app = express()
, server = app.listen(80)
, io = require('socket.io').listen(server)
, fs = require('fs')
var arr= [];
app.get('/aRoute', function(req, res) {
res.writeHead(200);
var data = {
// parse query string
};
arr.push(data);
io.sockets.emit('update', data);
res.end("OK");
});
app.get('/someOutput', function(req, res) {
res.writeHead(200);
res.end(JSON.stringify(footData));
});
io.sockets.on('connection', function (socket) {
});
I cut pasted part of it so now the first server script looks (roughly) like this.
// All imports
var express = require('express');
var routes = require('./routes');
var mongoose = require('mongoose');
var user = require('./routes/user');
var http = require('http');
var path = require('path');
var fs = require('fs');
var multer = require('multer');
var connect = require('connect');
var methodOverride = require('method-override');
var io = require('socket.io');
// middleware
// routes
// trying to make this a route
var arr= [];
app.get('/aRoute', function(req, res) {
res.writeHead(200);
var data = {
// parse query string
};
arr.push(data);
io.sockets.emit('update', data);
res.end("OK");
});
app.get('/someOutput', function(req, res) {
res.writeHead(200);
res.end(JSON.stringify(footData));
});
// THIS GIVES ME ERRORS RIGHT HERE
io.sockets.on('connection', function (socket) {
});
http.createServer(app, function(req, res){
// get files
// check for errors
}).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
Combining the two scripts has resulted in an error listed below at the line listed below.
io.sockets.on('connection', function (socket) {
^
TypeError: Cannot call method 'on' of undefined:
// THIS GIVES ME ERRORS RIGHT HERE
io.sockets.on('connection', function (socket) {
});
I don't understand why I'm getting this error after changing the two require statements and moving the server creation and listening to the bottom of the server. Does anyone know how I can fix this?
You're requiring socket.io, which has a .listen method, not an .on method. Once you call .listen, you'll get back an object that has the .on method you're trying to use.
io = require('socket.io').listen(server);
(You're also missing server, which is created in the second script by calling express().listen(somePortNumberLike80)
You can't just copy and paste code and expect it to work, really.

Categories

Resources