Middleware getting executed multiple times? - javascript

I am trying to make a url shortener app using express. I have 2 middle wares for routes /shorten/:url* and /:code respectively. Somehow when I make requests like /shorten/iamarshad.com (requests that are not formatted and will fail my validateUrl method), middleware handling that request gets executed sometimes twice and sometime thrice. Why is this happening ?
Code for route.js:
var express = require("express");
var router = express.Router();
var crypto = require("./crypto");
var styles = "<style>#import url('https://fonts.googleapis.com/css?family=Cormorant+Garamond');" +
"body{background: #fefefe; word-wrap: break-word;}" +
"p {font-size: 30px;color: #b33c66;font-family: 'Cormorant Garamond', monospace;text-align: center;" +
"margin-top: 40vh;font-weight: 500;word-spacing: 2px;}</style>";
function verifyUrl(req, res, next) {
console.log("/shorten middleware called");
req.params.url += req.params[0];
console.log(req.params.url);
if (validateUrl(req.params.url)) {
req.db.collection("counter")
.find({_id: "counter"})
.toArray(function (err, docs) {
if (err) console.error("Error occurred while getting COUNTER document:", err);
req.encodedId = crypto.encode(docs[0].count);
next();
});
}
else {
var elem = "<p>Please enter correct and formatted url!</p>";
res.send(styles + elem);
}
}
function incrementCounter(req, res, next) {
// increasing counter
req.db.collection("counter")
.update(
{
_id: "counter"
},
{
$inc : {
count : 1
}
}
);
next();
}
function insertUrlDocument(req, res, next) {
//inserting new url document
var obj = {original_url: req.params.url, _id: req.encodedId, entry_time: new Date().toUTCString()};
req.db.collection("urls")
.insert(obj, function(err, data) {
if(err) console.error("Error happened while adding new document:", err);
});
next();
}
function sendResponse(req, res) {
var elem = "<p>" + JSON.stringify({'original_url': req.params.url, 'short_url': 'https://shorten-that.herokuapp.com/' + req.encodedId}) + "</p>";
res.send(styles + elem);
}
function validateUrl(url) {
var format = /(http:\/\/|https:\/\/)[a-z0-9\-]+[.]\w+/;
return (format.test(url));
}
router.get("/:code", function(req, res) {
console.log("/:code middleware called with url", req.params.code);
var code = req.params.code.toString();
// searching short-url-id
req.db.collection("urls")
.find({_id: code})
.toArray(function(err, docs) {
if(err) console.error("Error occurred while searching urls:", err);
console.log(docs);
if(docs.length > 0)
res.redirect(docs[0]["original_url"]);
else {
var elem = "<p>Oops, wrong url requested!</p>";
res.send(styles + elem);
}
});
});
// better solution needed
router.get("/shorten/:url*", [verifyUrl, incrementCounter, insertUrlDocument, sendResponse]);
module.exports = router;
Code for server.js:
var express = require("express")
, mongo = require("mongodb").MongoClient
, port = process.env.PORT || 8080
, path = require("path")
, routes = require("./routes")
, favicon = require("serve-favicon");
var app = express();
app.use(favicon(path.join(__dirname, 'public','favicon.png')));
app.use(express.static(path.join(__dirname, "public")));
var url = 'mongodb://localhost:27017/url-shortener';
mongo.connect(url, function(err, db) {
if (err) console.error("Error occurred while connecting to db:", err);
console.log("successfully connected to db.");
app.use(function(req, res, next) {
req.db = db;
next();
});
app.use("/", routes);
});
app.listen(port, function() {
console.log("App running on", port);
});

Related

Node error handler bugs when using error pattern (err, req, res, next)

I am currently running node with the express middleware and handling request with the GET method. Errors like 404s or 500s are handled at the end of my script, after the GET method, but so far I have not been able to use Node's standard error handling method with err,req,res,next. The below code works fine for me. But ...
server.js
...
// Routing
app.use('/', function (req, res, next) {
req.const = {
nonce: nonce,
publicRoot: publicRoot,
client: client,
cachelifespan: cachelifespan
};
next();
}, router);
// Error handling
app.use('/', function (req, res, next) {
req.const = {
nonce: nonce,
publicRoot: publicRoot,
};
next();
}, errorHandler);
...
errorhandler.js:
...
errorHandler.use(function (req, res) {
let id = req.ip;
let url = req.url;
// Import
let nonce = req.const.nonce;
let publicRoot = req.const.publicRoot;
res.statusCode = 500;
let status = res.statusCode;
try {
let localPath = path.join(publicRoot, req.path);
fs.accessSync(localPath);
} catch (err) {
status = 404;
};
if (req.accepts('html')) {
try {
res.render('system/error', { title: status.toString(), description: 'This is an error!', nonce: 'nonceValue' }, function(err, html) {
html = html.replace("nonceValue", nonce);
res.send(html);
});
} catch (err) {
logError(id, status, req.url, err)
};
} else if (req.accepts('json')) {
res.send({ error: status.toString() });
} else {
res.type('txt').send("error: " + status.toString());
}
logError(id, status, req.url);
});
...
... if I try to write the app.use function to ...
app.use(function (err, req, res, next) {
... it bugs and Node's default error handler takes over.
I am not entirely sure how to fix that.
Or if I am doing the error handling right?
Any suggestions?
I found a solution to my problem.
Inside server.js (the main app js), I load the errorHandler in the beginning of the file:
const errorHandler = require('./errorhandler');
And in the last step, after the basic routing, I added the errorhandler:
// Routing
app.use('/', function (req, res, next) {
req.const = {
nonce: nonce,
publicRoot: publicRoot,
client: client,
cachelifespan: cachelifespan
};
next();
}, router);
// Error handling
app.use('/', function (req, res, next) {
req.const = {
nonce: nonce,
publicRoot: publicRoot,
};
next();
}, errorHandler);
Inside the separate errorhandler file:
//--------------------
// NODE
//--------------------
const express = require('express');
const errorHandler = express.Router();
//--------------------
// LOGGING
//--------------------
const { getDate, logOutput, logError } = require('./logger');
//--------------------
// ROUTER
//--------------------
errorHandler.use(function (req, res) {
let id = req.ip;
let url = req.url;
// Import
let nonce = req.const.nonce;
let publicRoot = req.const.publicRoot;
// Cookies
let insultor = "Samuel L Jackson says";
let insults = ['Motherfucker!!!', 'Son_of_a_bitch!!!', 'Asshole!!!', 'Punkass_motherfucker!!!', 'Whiny_little_bitch!!!', 'You_deserve_to_die_and_I_hope_you_burn_in_hell!!!', 'Web_motherfucker_do_you_speak_it?'];
let number = Math.floor(Math.random() * insults.length);
let insulted = false;
for (let [key, value] of Object.entries(req.cookies)) {
if (key.toString() == insultor) {
value = value.toString() + "_-_" + insults[number];
res.cookie(insultor, value);
insulted = true;
}
}
if (!insulted) {
res.cookie(insultor, insults[number]);
}
res.statusCode = 500;
let status = res.statusCode;
try {
let localPath = path.join(publicRoot, req.path);
fs.accessSync(localPath);
} catch (err) {
status = 404;
};
if (req.accepts('html')) {
try {
res.render('system/error', { title: status.toString(), description: 'This is an error, Motherfucker!', nonce: 'nonceValue' }, function(err, html) {
html = html.replace("nonceValue", nonce);
res.send(html);
});
} catch (err) {
logError(id, status, req.url, err)
};
} else if (req.accepts('json')) {
res.send({ error: status.toString() });
} else {
res.type('txt').send("error: " + status.toString());
}
logError(id, status, req.url);
});
module.exports = errorHandler;

How to implement membership functions using Express & MySQL and JWT

I currently implemented login and membership functions using Express & MySQL.
And I want to add JWT.
I wanted to create an API only through Postman, not on the Web, and I heard that I had to use Passport to search.
And I know there is also Express-generate, but I want to modify my current code.
I am a beginner in Node.js and want a guide.
app.js
var express = require('express');
var http = require('http');
var static = require('serve-static');
var path = require('path');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var expressSession = require('express-session');
var expressErrorHandler = require('express-error-handler');
var mysql = require('mysql');
var pool = mysql.createPool({
connectionLimit:10,
host:'localhost',
user:'root',
password:'password',
database:'test',
debug:false
});
var app = express();
app.set('port', 3000);
app.use('/public', static(path.join(__dirname, 'public')));
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(expressSession({
secret:'my key',
resave: true,
saveUninitialized:true
}));
var router = express.Router();
router.route('/process/login').post(function(req, res) {
console.log('/process/login');
var paramId = req.body.id;
var paramPassword = req.body.password;
console.log('request parameter:' + paramId + paramPassword);
authUser(paramId, paramPassword, function(err, rows) {
if (err) {
console.log('error');
res.writeHead(200, '{"Content-Type":"text/plain; charset=utf-8"}');
res.write('<h1>error</h1>');
red.end();
return;
}
if (rows) {
console.dir(rows);
res.writeHead(200, '{"Content-Type":"text/plain; charset=utf-8"}');
res.write('<h1>user login success</h1>');
res.write('<div><p>user:' + rows[0].id + ' </p></div>');
res.end();
} else {
res.writeHead(200, '{"Content-Type":"text/plain; charset=utf-8"}');
res.write('<h1>user not found</h1>');
res.end();
}
});
});
router.route('/process/adduser').post(function(req, res) {
console.log('/process/adduser');
var paramId = req.body.id;
var paramPassword = req.body.password;
console.log('request parameter' + paramId + paramPassword);
addUser(paramId, paramPassword, function(err, addedUser) {
if (err) {
console.log('error');
res.writeHead(200, '{"Content-Type":"text/plain; charset=utf-8"}');
res.write('<h1>error</h1>');
red.end();
return;
}
if (addedUser) {
console.dir(addedUser);
res.writeHead(200, '{"Content-Type":"text/plain; charset=utf-8"}');
res.write('<h1>user added</h1>');
res.end();
} else {
res.writeHead(200, '{"Content-Type":"text/plain; charset=utf-8"}');
res.write('<h1>user added fail</h1>');
res.end();
}
});
})
app.use('/', router);
var addUser = function(id, password, callback) {
console.log('addUser');
pool.getConnection(function(err, conn) {
if(err) {
if (conn) {
conn.release();
}
callback(err, null);
return;
}
console.log('db threadid' + conn.threadId);
var data = {id:id, password:password};
var exec = conn.query('insert into users set ?', data,
function(err , result) {
conn.release();
console.log('SQL syntax' + exec.sql);
if (err) {
console.log('SQL error;');
callback(err, null);
return;
}
callback(null, result);
});
});
};
var authUser = function(id, password, callback) {
console.log('authUser' + id + password);
pool.getConnection(function(err, conn) {
if (err) {
if (conn) {
conn.release();
}
callback(err, null);
return;
}
console.log('db threadid:'+ conn.threadId);
var tablename = 'users';
var columns = ['id'];
var exec = conn.query('select ?? from ?? where id = ? and password = ?', [columns, tablename, id, password],
function(err, rows) {
conn.release();
console.log('SQL syntax' + exec.sql);
if (err) {
callback(err, null);
return;
}
if (rows.length >0 ) {
console.log('user find');
callback(null, rows);
} else {
console.log('user not found');
callback(null, null);
}
});
});
};
var errorHandler = expressErrorHandler({
static: {
'404' : './public/404.html'
}
});
app.use(expressErrorHandler.httpError(404));
app.use(errorHandler);
var server = http.createServer(app).listen(app.get('port'), function() {
console.log('server start' + app.get('port'));
});
Hi #yori If you want to create an API, first I will recommend parsing your data as JSON objects and thus eliminating all HTML tags in your code.
In order to use JWT for authentication, you will have to install the jsonwebtoken package as part of your project dependencies: https://www.npmjs.com/package/jsonwebtoken
I will recommend following the in-depth instructions in this post as a guide: https://medium.freecodecamp.org/securing-node-js-restful-apis-with-json-web-tokens-9f811a92bb52
For scope though, here is some explanation:
Express can be used to build robust APIs which can be made available for consumption. POSTMAN is a GUI tool that developers use to query APIs. curl commands is the terminal alternative. JWT is a safe way of representating claims transfered between two parties. I see the need to break down these terms to you so that you will understand the need, relevance and difference between each tool.
Following the guide in the article you will have to refactor your code a little bit.

"callback is not defined" in node js

This is part of my code, and it doesn't work. It says,
ReferenceError: callback is not defined
at C:\js\kweb-hw\routes\board.js:14:13
var express = require('express');
var router = express.Router();
var mysql_db = require('../db/db_con')();
var pool = mysql_db.init();
/* GET home page. */
router.get('/', function(req, res, next) {
pool.getConnection(function (err,conn) {
if(err) {
if(conn) {
conn.release();
}
callback(err,null);
return;
}
var sql = "SELECT * FROM board";
var exec = conn.query(sql,[] ,function(err, rows) {
conn.release();
if (err) throw err;
res.render('board', { rows: rows });
});
});
});
You don't need a callback in this case, because you're at the end of your route, so to speak.
So instead, you could do something like handle it with sending an error message to your rendered page.
var express = require('express');
var router = express.Router();
var mysql_db = require('../db/db_con')();
var pool = mysql_db.init();
/* GET home page. */
router.get('/', function(req, res, next) {
pool.getConnection(function (err,conn) {
if(err) {
if(conn) {
conn.release();
}
res.render('board',{rows: [],error:'Could not connect'});
}else{
var sql = "SELECT * FROM board";
var exec = conn.query(sql,[] ,function(err, rows) {
conn.release();
if (err) throw err;
res.render('board', { rows: rows });
});
}
});
});

in node.js with express req.session is undefined inside my require() module

I'm wondering why req.session.username is undefined in the tag >>>DOESNT WORK<<< while it does work in the tag >>>THIS DOES WORK<<< . I brought in req as an argument to my module but it seems I'm supposed to do something else? The /ajax route is accessed via a ajax call and it does set the session variable in >>>THIS DOES WORK<<<
//index.js file
var express = require('express');
var router = express.Router();
var app = express();
var functions = require('../public/javascripts/functions.js');
router.post('/ajax', function(req, res , next){
var username = req.param("username");
var password = req.param("password");
var operation = req.param("operation");
else if (operation === "validate")
{
async.series([
function()
{
functions.validate(username, password, req);
}
], function(err,result)
{
if (err)
return console.log(err);
console.log(result);
});
//req.session.username = "yaryar"; >>>THIS DOES WORK<<<
}
var strings = ["rad", "bla", "ska"]
console.log('body: ' + JSON.stringify(req.body));
console.log("AJAX RECEIVED");
res.send(strings);
});
module.exports = router;
functions.js file:
module.exports = {
validate: function(username, password, req) {
var url = 'mongodb://localhost';
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
MongoClient.connect(url, function(err, db)
{
assert.equal(null, err);
console.log("Connected correctly to server.");
var cursor = db.collection('users').find({username : username});
cursor.each(function(err,doc,req)
{
assert.equal(err, null);
if (doc != null)
{
console.log("user found: " + doc.username);
req.session.username = "ttyy"; // >>>DOESNT WORK<<<
return true
}
else
{
console.log("user not found");
return false;
}
});
//db.close();
});
}
};
you're overwriting req by doing cursor.each(function(err,doc,req) change it to cursor.each(function(err,doc,arr) and it will work

Node.js Error: Route.get() requires callback functions but got a [object Undefined]

Hello i know that this question is common in stackoverflow but i passed by all of them and i really cannot get what is wrong with my code.
This is my main server.js
var dbUri = process.env.MONGODB_URI;
var app = express();
var PORT = process.env.PORT || 3001;
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
if (app.settings.env === 'development') {
dbUri = 'mongodb://localhost/barsDb';
}
mongoose.connect(dbUri, function (err, res) {
if (err) {
console.log('Erorr connection to database ' + dbUri + '.' + err);
} else {
console.log('Connected to database on ' + dbUri + "\n");
}
});
//app.use(require('./routes.bars'));
require('./routes.bars')(app); //error here reciving undefined
// connect to server
app.listen(PORT, function () {
console.log('Listening to port ' + PORT + '...');
});
These are my routes.js
var bars = require('./controllers/controller.bar');
var mongoose = require('mongoose');
module.exports = function(app) {
app.route('/').get(bars.getMain); //error in this line it is returning undefinded.
app.route('/bars').get(bars.getBars);
app.route('/bars').post(bars.addBar);
app.route('/bars/:id').put(bars.updateBarById);
app.route('/bars/:loc').get(bars.getByLocation);
app.route('/bars/:id').get(bars.getBarById);
app.route('/bars/:id').delete(bars.deletBarById);
};
This is my controller:
var mongoose = require('mongoose');
var dbModel = require('./../model/bars.db');
var path = require('path');
var _ = require('underscore');
// main page
module.getMain = function (req, res) {
res.sendFile(path.join(__dirname + "/../public/index.html"));
};
// post new bar
module.addBar = function (req, res) {
var body = _.pick(req.body,'name', 'address', 'phone', 'barType', 'ambient', 'options', 'loc');
console.log(body);
var newBar = new dbModel(body);
newBar.save(function (err) {
if (err) throw err;
//res.send('Bar Created');
res.status(201).send();
});
};
// get all bars
module.getBars = function (req, res) {
dbModel.find({},function (err, bars) {
if (err) throw err;
res.json(bars);
//res.status(200).send();
});
};
//get bars by location
module.getByLocation = function (req, res) {
var barLoc = req.params.loc.split(",");
var barLocLon = parseFloat(barLoc[0]);//.toFixed(5);
var barLocLat = parseFloat(barLoc[1]);//.toFixed(5);
barLoc = []; barLoc.push(barLocLon); barLoc.push(barLocLat);
dbModel.find({
loc: {$gt:[barLocLon - 0.0200, barLocLat - 0.0200], $lt:[barLocLon + 0.0200, barLocLat + 0.0200]}
}, function (err, bars) {
if (err) throw err;
res.json(bars);
res.status(200).send();
});
};
// get bar by id:
module.getBarbyId = function (req, res) {
var barId = req.params.id;
dbModel.findById(barId, function (err, bar) {
if (err) throw err;
res.json(bar);
res.status(200).send();
});
};
// update bar by id:
module.updateBarById = function (req, res) {
var barId = req.params.id;
var body = _.pick(req.body,'name', 'address', 'phone', 'barType', 'ambient', 'options', 'loc');
dbModel.findById(barId, function (err, bar) {
if (bar) {
bar.save(function (err) {
if (err) throw err;
});
}
});
dbModel.findByIdAndUpdate(barId, {$set:req.body}, function (err, bar) {
if (err) throw err;
res.send('Updated');
});
};
// delete bar by id:
module.deleteBarById = function (req, res) {
var barId = req.params.id;
//console.log(barId);
dbModel.findByIdAndRemove(barId, function (err) {
if (err) throw err;
res.send('Deleted id ' + barId);
});
};
Wrap your functions like this.
var myFunctions = {
// get bar by id:
getBarbyId: function (req, res) {
var barId = req.params.id;
dbModel.findById(barId, function (err, bar) {
if (err) throw err;
res.json(bar);
res.status(200).send();
});
},
// update bar by id:
updateBarById: function (req, res) {
var barId = req.params.id;
var body = _.pick(req.body, 'name', 'address', 'phone', 'barType', 'ambient', 'options', 'loc');
dbModel.findById(barId, function (err, bar) {
if (bar) {
bar.save(function (err) {
if (err) throw err;
});
}
});
dbModel.findByIdAndUpdate(barId, {
$set: req.body
}, function (err, bar) {
if (err) throw err;
res.send('Updated');
});
},
// delete bar by id:
deleteBarById: function (req, res) {
var barId = req.params.id;
//console.log(barId);
dbModel.findByIdAndRemove(barId, function (err) {
if (err) throw err;
res.send('Deleted id ' + barId);
});
}
}
module.exports = myFunctions;
Now you can you use your "controller" like this:
var myControllerFuncs = require('path/controller.js');
//myControllerFuncs.updateBarById...

Categories