Nodejs and mongodb connection error after upgrading Mongo - javascript

Am trying to build some Todo app using Express and mongodb but i have some problems with nodejs and mongo connection and i searched about it on internet but didn't get any solution for my problem.
When trying to connect to mongodb from node js as in this code:
// This to require Express framework to use it
const express = require('express');
const csrf = require('csurf');
const errorhandler = require('errorhandler')
// Loads the piece of middleware for sessions
const logger = require('morgan');
const favicon = require('serve-favicon');
const methodOverride = require('method-override');
// This is a middleware to handle requests and parse the forms
const bodyParser = require('body-parser');
const routes = require('./routes');
const tasks = require('./routes/tasks');
const http = require('http');
const path = require('path');
const mongoskin = require('mongoskin');
const cookieParser = require('cookie-parser');
const session = require('express-session');
const db = mongoskin.db("mongodb://localhost:27017/todo");
// Define object of express
const app = express();
app.use((req, res, next) => {
req.db = {};
req.db.tasks = db.collection('tasks');
next();
});
// This makes us can access app name from any JADe template
app.locals.appname = "Todo App Express.js";
app.locals.moment = require('moment');
// set app port to 8081 port
app.set('port', 8081);
// these tells express where's project safe templates in, and tell what's
// their extension will be.
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
// show express favicon in browser
app.use(favicon(path.join('public', 'favicon.ico')));
// this will print requests in terminal
app.use(logger('dev'));
// using body parser to can parse requests
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(methodOverride());
// to use CSRF we need cookie parser
app.use(cookieParser('CEAF3FA4-F385-49AA-8FE4-54766A9874F1'));
app.use(session({
secret: '59B93087-78BC-4EB9-993A-A61FC844F6C9',
resave: true,
saveUninitialized: true
}));
app.use( csrf() );
// to process LESS stylesheets into CSS ones
app.use(require('less-middleware')(path.join(__dirname, 'public')));
// to use other static files which inside public
app.use(express.static(path.join(__dirname, '/public')));
// to make csrf used in templates
app.use( (req, res, next) => {
res.locals._csrf = req.csrfToken();
return next();
});
app.param('task_id', (req, res, next, taskId) => {
req.db.tasks.findById(taskId, (error, task) => {
if (error) return next(error);
if (!task) return next(new Error('Task is not found.'));
req.task = task;
return next();
});
});
// homepage to show our todo homepage
app.get('/', routes.index);
// list all created tasks [in-progress ones]
app.get('/tasks', tasks.list);
// this to mark all task as completed in one step
app.post('/tasks', tasks.markAllcompleted);
// this to add new task
app.post('/tasks', tasks.add);
// this to mark specfic task as completed
app.post('/tasks/:task_id', tasks.markcompleted);
// this to delete specfic task by :task_id
app.delete('/tasks/:task_id', tasks.del);
// this to list all completed tasks
app.get('/tasks/completed', tasks.completed);
// this 404 error page to show it if user requested any route doesn't exist in our routes
app.all('*', (req, res) => {
res.status(404).send();
});
if ('development' == app.get('env')) {
app.use(errorhandler());
}
// create our server
http.createServer(app).listen(app.get('port'),
() => {
console.log('Express server listening on port ' + app.get('port'));
});
I go this error in terminal:
/home/luffy/nodejs-train/todo-express-mongodb/node_modules/mongodb/lib/mongo_client.js:804
throw err;
^
TypeError: Cannot read property 'apply' of undefined
at EventEmitter.<anonymous> (/home/luffy/nodejs-train/todo-express-mongodb/node_modules/mongoskin/lib/collection.js:51:21)
at Object.onceWrapper (events.js:272:13)
at EventEmitter.emit (events.js:180:13)
at /home/luffy/nodejs-train/todo-express-mongodb/node_modules/mongoskin/lib/utils.js:134:27
at result (/home/luffy/nodejs-train/todo-express-mongodb/node_modules/mongodb/lib/utils.js:414:17)
at executeCallback (/home/luffy/nodejs-train/todo-express-mongodb/node_modules/mongodb/lib/utils.js:406:9)
at /home/luffy/nodejs-train/todo-express-mongodb/node_modules/mongodb/lib/mongo_client.js:271:5
at connectCallback (/home/luffy/nodejs-train/todo-express-mongodb/node_modules/mongodb/lib/mongo_client.js:940:5)
at /home/luffy/nodejs-train/todo-express-mongodb/node_modules/mongodb/lib/mongo_client.js:801:11
at process._tickCallback (internal/process/next_tick.js:112:11)
[nodemon] app crashed - waiting for file changes before starting...
And in my Firefox got :
Unable to connect
Firefox can’t establish a connection to the server at localhost:8081.
Using NodeJS V9.8.0 and mongodb v3.4.14

This was a problem even we faced and it seems it just has to do with the consequent versions of 'mongoskin'. Why don't you try and use mongodb ?
Saves time and a much better option!

Related

node-postgres queries not returning anything in Express routes async routes

I'm trying to run a simple query from an express route:
var router = require('express-promise-router')()
const { Pool } = require('pg')
const pool = new Pool({
user: 'user',
password: 'password',
host: 'host',
port: 1234,
database: 'db'
})
router.get('/', async (req, res) => {
console.log('OK')
try {
const { rows } = await pool.query('Select VERSION()')
console.log(rows)
}
catch(e) {
console.log(e)
}
console.log('DONE')
})
module.exports = router
'OK' Prints after sending the request but rows, e, or 'DONE' never print. I'm following the async/await method directly from https://node-postgres.com/guides/async-express.
I've also came across a thread for koa-router where people were having issues with async await calls because of some middle-ware they added that wasn't synchronous
https://github.com/ZijianHe/koa-router/issues/358.
I'm not sure what middle-ware would cause this but here's my app.js that initializes all middle-ware:
var createError = require('http-errors');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require("cors");
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var dataRouter = require("./routes/data");
var uploadRouter = require("./routes/upload")
var fundingRouter = require('./routes/chartData/fundingOverview')
var testRouter = require('./routes/test')
var authRouter = require('./routes/auth')
var session = require('express-session')
var MongoStore = require('connect-mongo')(session)
var passport = require('passport')
const config = require('config')
const mongo = config.get('mongo')
const mongoose = require('mongoose')
mongoose.connect(mongo, {
useUnifiedTopology: true,
useNewUrlParser: true,
useFindAndModify: false
}).then(res => {
console.log('connected')
}).catch(err => {
console.log(err)
})
var express = require('express');
const mountRoutes = require('./routes')
var app = express();
const bodyParser = require('body-parser')
app.use(bodyParser.json())
mountRoutes(app)
app.use(cors())
var sessionMiddleWare = session({
secret: 'top session secret',
store: new MongoStore({ mongooseConnection: mongoose.connection }),
resave: true,
saveUninitialized: true,
unset: 'destroy',
cookie: {
httpOnly: false,
maxAge: 1000 * 3600 * 24,
secure: false, // this need to be false if https is not used. Otherwise, cookie will not be sent.
}
})
app.use(sessionMiddleWare)
// Run production React server on Node server
if(process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
// End Run production React Server on Node Server
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// app.use('/upload', uploadRouter)
// app.use('/', indexRouter);
// app.use('/users', usersRouter);
// app.use('/data', dataRouter)
// app.use('/funding', fundingRouter)
// app.use('/login', usersRouter)
// app.use('/auth', authRouter)
// catch 404 and forward to error handler
// app.use(function(req, res, next) {
// next(createError(404));
// });
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
I'm mounting the routes directly after body parser. That's the only middle-ware that's called before the routes and is required in order for me to get data into the back end.
I'm able to execute that simple query by putting it into a script file and running 'node test.js' (I.E without the router) and it works fine so I know it's not a problem with node-postgre.
I know this is a problem with the call stack not being totally synchronous but I'm confused as to what's not at this point. I even made the axios call on the front-end async/await with no luck (I don't think it was necessary though).
Any guidance would be help a lot.
EDIT:
I created a fresh express skeleton and hooked my front-end to make a call to a route on the new express server with the same code, it worked. It led me to discover the call wasn't being completed because I was running the server with Nodemon. When I start the server using 'yarn start' the async calls get processed correctly. The question now is what in nodemon makes async router calls not work?
You need to finish the request/response cycle in your middleware.
So in your code:
router.get('/', async (req, res) => {
console.log('OK')
try {
const { rows } = await pool.query('Select VERSION()')
console.log(rows)
res.status(200).json(rows)
}
catch(e) {
console.log(e)
res.status(500).json(e)
}
console.log('DONE')
})

Node server response is HTML after adding catch-all to allow react-router to work

I have been developing a node backend, react front end web app for a couple months. It has working just fine when I started the server via nodemon and the front end with npm start. But now that I am getting ready to host an alpha version and ran 'npm run build' I've been running into issues.
It seems to be stemming from the interaction of accessing the app from the server's port and react-router. I added a catch-all endpoint app.get('/*'...) to my server to allow the react-router to work. So now when the front requests data, the response is HTML not the array I want.
I feel like there is a simple solution to this, but I just don't see it yet. I looked into using HashRouter instead of BrowserRouter, but unfortunately I can't use that because I am using MSAL Active Directory for login.
server/index.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors')
require('dotenv').config();
const massive = require('massive');
const session = require("express-session");
const morgan = require('morgan');
const path = require('path');
const ctrl = require(`./controllers/controller.js`);
//Middleware
const app = express();
app.use(bodyParser.json());
app.use(cors());
app.use(express.static(__dirname + './../build'));
app.use(morgan('dev'));
//Connection to Azure DB
massive(process.env.CONNECTION_STRING)
.then(db => {
console.log('Connected to Azure PostgreSQL Database')
app.set('db', db)
}).catch(err=>console.log(err))
app.use(session({
secret: process.env.SESSION_SECRET,
cookie: { maxAge: 60000 },
resave: false,
saveUninitialized: true
}));
//Endpoints
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, './../build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
})
app.get('/getallemployees/', ctrl.getAllEmployees)
app.listen(8080, () => console.log(`Listening on ${8080}`));
Put that catch-all endpoint after all the others that return data.
//Endpoints
app.get('/getallemployees/', ctrl.getAllEmployees)
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, './../build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
})

Req.Body is returning "undefined" values

I have added body-parser to my application app.js file. I have a routes folder and a controllers folder which handles my request.
Initially, I did not have body-parser added to my application. When I added body-parser and console logged req.body I got an empty object. When I console logged req.body.email, req.body.password, and req.body.displayName values from postman were read as undefined.
app.js
let createError = require('http-errors');
let express = require('express');
let path = require('path');
let cookieParser = require('cookie-parser');
let logger = require('morgan');
let bodyParser = require('body-parser');
let assert = require('assert');
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config()
}
let usersRouter = require('./routes/user');
let app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/user', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
// MongoDB Connection
const db = {};
const MongoClient = require('mongodb').MongoClient;
MongoClient.connect(process.env.MONGODB_CONNECT_URL, (err, client) => {
// Connection works dont worry about it
});
module.exports = app;
routes/user.js
const express = require('express');
const router = express.Router();
const user = require('../controllers/user');
router.post('/', user.createUser);
router.delete('/:id', user.deleteUser);
router.get('/:id', user.loginUser);
module.exports = router;
controllers/user.js
const bcrypt = require('bcryptjs');
const Joi = require('joi');
const ObjectId = require('mongodb').ObjectID;
exports.createUser = async (req, res, next) => {
console.log('Request body: ', req.body);
const email = req.body.email;
const password = req.body.password;
const displayName = req.body.displayName;
console.log('Email: ', email);
console.log('Password: ', password);
console.log('Display name: ', displayName);
};
Please make sure that you are adding content-type header in postman content-type : application/json also in body tab select raw and beside raw select json from drop-down list.
Check this
https://i.stack.imgur.com/ZDhcl.png
You are probably trying to send form-data with Postman which sends a multipar body, body parser cannot handle multipart bodies. For handling multipart bodies you have to use a different module, I normally use multer.
With multer installed you just have to include it and it as middleware (under you body-parser for instance) using none() since in this case you want to handle text-only multipart body (More information about this in multer docs
let multer = require('multer');
app.use(multer().none());
Besides that I wanted to mention you are including two body parsers in your code, the express body parser
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
and an external body-parser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
Pick one, you don't need both, the best option for me would be to keep the one that comes with express, this way you don't have to install any more external packages.

How can I make session variables accessible to sub application

I am building an api that will interface with the MongoDB database and have mounted it as a subapplication. I have defined a session variable in my server controller.
However, any time that the server files need to talk to the api files the session variables are never passed off.
Heres the app.js file
//app.js file
'use strict';
process.env.NODE_ENV = 'development';
var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var flash = require('connect-flash');
var helmet = require('helmet');
var app = express();
app.use(helmet());
var port = process.env.PORT || 3000;
mongoose.connect("mongodb://localhost:27017/striv4");
var db = mongoose.connection;
// mongo error
db.on('error', console.error.bind(console, 'connection error:'));
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: false,
store: new MongoStore({
mongooseConnection: db
})
}));
app.use(flash());
// make user ID available in templates
app.use(function (req, res, next) {
res.locals.currentUser = {
username:req.session.username,
id: req.session.userId
};
next();
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('secreter'));
app.use(logger('dev'));
var api = require('./app_api/routes/index');
var serverRoutes = require('./server/routes/index');
//static file middleware
app.use(express.static(__dirname + '/public'));
app.set('views',__dirname +'/server/views');
app.set('view engine','pug');
app.use('/',serverRoutes);
app.use('/api',api);
//custom error handler
app.use(function(error, req, res, next) {
res.status(error.status || 500);
res.send('Error: '+error.message);
});
app.listen(port);
console.log('Listening on port: '+port);
You've got the whole program listed so there is more than one way for this to have gone wrong. Here are my suggestions to fix this:
Check the version of express-session you've installed. (Just run npm ls in the terminal and in your root Node app folder where you're package.json file is). If it's equal to or greater than v1.5.0, you don't need the cookie-parser for sessions anymore. Comment out the app.use line for the cookie parser and see if this works.
If you still need cookie parser for some other reason, you should use the same secret for sessions and the cookie parser. In your code, you've set two different values for secret.
I've seen that the other big failure for sessions occurs if the session store is not correctly connected to your Node app. Cross-check that the database is available and working. In my experience, Express sessions will fail silently if it can't get to the DB.
Hope this helps.

How to fetch images from node.js server's folder in URL?

Does anybody know how to fetch images from node.js server's folder in URL?
In my folder structure I have folder data and inside there is subfolder img with image. I want to access this image with URL, like this:
http://localhost:3000/data/img/default.jpg
but when I enter it into browser I always get this error:
Page Not Found /data/img/default.jpg is not a valid path.
server.js:
'use strict';
/**
* Module dependencies.
*/
var init = require('./config/init')(),
config = require('./config/config'),
mongoose = require('mongoose');
var express = require('express');
/**
* Main application entry file.
* Please note that the order of loading is important.
*/
// Bootstrap db connection
var db = mongoose.connect(config.db, function(err) {
if (err) {
console.error('\x1b[31m', 'Could not connect to MongoDB!');
console.log(err);
}
});
// Init the express application
var app = require('./config/express')(db);
// Bootstrap passport config
require('./config/passport')();
app.use(express.static('data/img'));
// Start the app by listening on <port>
app.listen(config.port);
// Expose app
exports = module.exports = app;
// Logging initialization
console.log('MEAN.JS application started on port ' + config.port);
express.js:
'use strict';
/**
* Module dependencies.
*/
var express = require('express'),
morgan = require('morgan'),
bodyParser = require('body-parser'),
session = require('express-session'),
compress = require('compression'),
methodOverride = require('method-override'),
cookieParser = require('cookie-parser'),
helmet = require('helmet'),
passport = require('passport'),
mongoStore = require('connect-mongo')({
session: session
}),
flash = require('connect-flash'),
config = require('./config'),
consolidate = require('consolidate'),
path = require('path');
module.exports = function(db) {
// Initialize express app
var app = express();
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
require(path.resolve(modelPath));
});
// Setting application local variables
app.locals.title = config.app.title;
app.locals.description = config.app.description;
app.locals.keywords = config.app.keywords;
app.locals.facebookAppId = config.facebook.clientID;
app.locals.jsFiles = config.getJavaScriptAssets();
app.locals.cssFiles = config.getCSSAssets();
// Passing the request url to environment locals
app.use(function(req, res, next) {
res.locals.url = req.protocol + '://' + req.headers.host + req.url;
next();
});
// Should be placed before express.static
app.use(compress({
filter: function(req, res) {
return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
},
level: 9
}));
// Showing stack errors
app.set('showStackError', true);
// Set swig as the template engine
app.engine('server.view.html', consolidate[config.templateEngine]);
// Set views path and view engine
app.set('view engine', 'server.view.html');
app.set('views', './app/views');
// Environment dependent middleware
if (process.env.NODE_ENV === 'development') {
// Enable logger (morgan)
app.use(morgan('dev'));
// Disable views cache
app.set('view cache', false);
} else if (process.env.NODE_ENV === 'production') {
app.locals.cache = 'memory';
}
// Request body parsing middleware should be above methodOverride
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(methodOverride());
// Enable jsonp
app.enable('jsonp callback');
// CookieParser should be above session
app.use(cookieParser());
// Express MongoDB session storage
app.use(session({
saveUninitialized: true,
resave: true,
secret: config.sessionSecret,
store: new mongoStore({
db: db.connection.db,
collection: config.sessionCollection
})
}));
// use passport session
app.use(passport.initialize());
app.use(passport.session());
// connect flash for flash messages
app.use(flash());
// Use helmet to secure Express headers
app.use(helmet.xframe());
app.use(helmet.xssFilter());
app.use(helmet.nosniff());
app.use(helmet.ienoopen());
app.disable('x-powered-by');
// Setting the app router and static folder
app.use(express.static(path.resolve('./public')));
// Globbing routing files
config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
// Assume 'not found' in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.
app.use(function(err, req, res, next) {
// If the error object doesn't exists
if (!err) return next();
// Log it
console.error(err.stack);
// Error page
res.status(500).render('500', {
error: err.stack
});
});
// Assume 404 since no middleware responded
app.use(function(req, res) {
res.status(404).render('404', {
url: req.originalUrl,
error: 'Not Found'
});
});
return app;
};
It's like you have already set your data/img folder as a static folder in the line below:
app.use(express.static('data/img'));
In that case, you should be accessing images placed in the static folder above using below url:
http://localhost:3000/default.jpg
I will however advice you use Node's global variable __dirname to indicate the root of the static folder but this depends on where your server.js is located within your file structure.
The js file containing the snippets below is located in the root and I have /data/img folder from the root as well and I am able to retrieve the image using /image name.
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/data/img'));
app.listen(3500, function () {
console.log('Express server is listening, use this url - localhost:3500/default.png');
});
See if this helps you. If it does, make sure you know the reason for using the __dirname global variable name.
SO1

Categories