I am trying to store my node rest api data to mongodb atlas. But getting insertion errors - mongodb

I am trying to register the user to mongodb atlas for registration and login but i am geting an error 404.
here is full link to mycode
https://github.com/badrinathareddyr/falcon.git
server.js file
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const authRoute = require('../backend/routes/auth')
//connect to database
dotenv.config({ path: __dirname + '/.env' });
mongoose.connect(
process.env[DB_CONNECT], { useNewUrlParser: true }, () =>
console.log('connected to db!')
);
//Middleware
app.use(express.json());
//middlewareroutes
app.use('/register', authRoute);
app.listen(3000, () => console.log('server up and running'));
auth.js file
var express = require('express');
const router = express.Router();
const User = require('../models/User');
const bcrypt = require('bcryptjs');
router.post('/register', function (req, res) {
if (!req.body.email || !req.body.password) {
res.json({ success: false, msg: 'Please pass email and password.' });
} else {
var newUser = new User({
email: req.body.email,
password: req.body.password
});
// save the user
newUser.save(function (err) {
if (err) {
return res.json({ success: false, msg: 'Email already exists.' });
}
res.json({ success: true, msg: 'Successful created new user.' });
});
}
});
module.exports = router;

It's because of process.env.DB_CONNECT in your code is undefined. Change line 5 of your src/backend/server.js file like below:
const dotenv = require('dotenv').config({ path: __dirname + '/.env' });
then comment dotenv.config()
and copy .env to src/backend/.
Or change line 10 or the file like this:
dotenv.config({ path: __dirname + '/.env' });
You have const User = require('../models/User'); two time in backend/routes/auth.js. Comment line 9. It will give you error.
I fixed it and created pull request in github. Merge it.

Related

MongooseError: Operation `users.findOne()` buffering timed out after 10000ms. How do I resolve this?

Error:
MongooseError: Operation `users.findOne()` buffering timed out after 10000ms
at Timeout.<anonymous> (D:\Web Dev\Traversy\storybooks\node_modules\mongoose\lib\drivers\node-mongodb-native\collection.js:153:23)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7)
GET /auth/google/callback?code=4%2F0ARtbsJqsdI35M7-9iSldOa1xWXs9SXFW09MohqzZ94_K5I5jpc1YTKge6lGKuS8-jPRyZA&scope=profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile - - ms - -
What I tried to do:
mongoose.connect(...) code is loading except this is my code where I tried to comment out: useFindAndModify: true
db.js
const mongoose = require('mongoose')
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
// useFindAndModify: true
})
console.log(`MongoDB Connected: ${conn.connection.host}`)
} catch(err) {
console.error(err)
process.exit(1)
}
}
module.exports = connectDB
auth.js
const express = require('express')
const passport = require('passport')
const router = express.Router()
// #desc Auth with Google
// #route GET /auth/google
router.get('/google', passport.authenticate('google', { scope: ['profile'] }))
// #desc Google auth callback
// #route GET /auth/google/callback
router.get('/google/callback', passport.authenticate('google', { failureRedirect: '/' }),
(req, res) => {
res.redirect('/dashboard')
})
module.exports = router
passport.js
const GoogleStrategy = require('passport-google-oauth20').Strategy
const mongoose = require('mongoose')
const User = require('../models/User')
module.exports = function (passport) {
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback'
},
async (accessToken, refreshToken, profile, done) => {
// console.log(profile)
const newUser = {
googleId: profile.id,
displayName: profile.displayName,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
image: profile.photos[0].value
}
try {
let user = await User.findOne({ googleId: profile.id })
if (user) {
done(null, user)
} else {
user = await User.create(newUser)
done(null, user)
}
} catch (err) {
console.error(err)
}
}))
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => done(err, user))
})
}
App.js
const path = require('path')
const express = require('express')
const dotenv = require('dotenv')
const morgan = require('morgan')
const exphbs = require('express-handlebars')
const passport = require('passport')
const session = require('express-session')
const connectDB = require('./config/db')
// Load config
dotenv.config({ path: './config/config.env' })
// Passport config
require('./config/passport')(passport)
connectDB()
const app = express()
// Logging
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'))
}
// Handlebars (Source: https://www.npmjs.com/package/express-handlebars)
app.engine('.hbs', exphbs.engine({ defaultLayout: 'main', extname: '.hbs' }))
app.set('view engine', '.hbs')
// Sessions
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false
}))
// Passport middleware
app.use(passport.initialize())
app.use(passport.session())
// Static folder
app.use(express.static(path.join(__dirname, 'public')))
// Routes
app.use('/', require('./routes/index'))
app.use('/auth', require('./routes/auth'))
const PORT = process.env.PORT || 3000
app.listen(PORT, console.log(`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`))

Passport.js error of "Unknown authentication strategy "local"' for user authentication

I've worked through other Stack Overflow posts about the "Unknown authentication strategy" error, but none of the posted solutions solved my problem. I've used the passport.js tutorial at https://www.passportjs.org/howtos/password/ as a guide while trying to enable user authentication for my Express/MongoDB web application, but have been unable to progress due to this error.
I'm receiving the below error in the browser when I click 'Submit' after typing in an email and password to my form:
I'm also receiving the below errors in the console:
Below is code in my auth.js file, which defines the passport strategy and handles creating sessions with serializeUser and deserializeUser. The verify function I'm passing into the LocalStrategy constructor isn't entirely developed. I wanted to ensure that passport.js would at least return an error message when it didn't find the testemail#test.com email in MongoDB before writing the code that would determine when a user's email was actually in the database.
const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local')
const { MongoClient } = require("mongodb");
const url = mongoDBConnectionString; // I have inserted a placeholder for my connection string because I don't want to post it on Stack Overflow.
const client = new MongoClient(url);
passport.use(new LocalStrategy(async function verify(email, password, cb) {
await client.connect(); // Connect to the MongoDB Atlas instance at the above url.
const db = client.db("users"); // Connect to the "users" database.
const col = db.collection("userLogins"); // Use the collection "userLogins".
const user = await col.findOne({email_address: email}); // Determine if a user exists with a specific email address.
await client.close();
return cb(null, false, { message: "Incorrect username or password."});
passport.serializeUser(function(user, cb) {
process.nextTick(function() {
return cb(null, { id: user.id, username: user.username });
});
});
passport.deserializeUser(function(user, cb) {
process.nextTick(function() {
return cb(null, user);
});
});
Below is the code in my app.js file where I have the "/login/password" POST route defined.
const express = require('express')
const session = require('express-session');
const passport = require('passport');
const LocalStrategy = require('passport-local')
const bodyParser = require('body-parser');
const { MongoClient } = require("mongodb");
const app = express();
app.use(express.static(__dirname + '/public'));
app.use(bodyParser.urlencoded({extended: true}))
app.use(bodyParser.json())
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
cookie: { secure: true }
}));
app.use(passport.authenticate('session'));
.
.
.
.
app.post('/login/password', passport.authenticate('local', {
successReturnToOrRedirect: '/',
failureRedirect: '/login',
failureMessage: true
}));

req.session.user gives 'undifined' as output

I am implementing a login authentication program in MERN stack.
When I enter correct user name and password, login function works fine.
There are some components which can be displayed only if the client is logged in. Therefore, to validate the client I have implemented authenticator function in the server which should return success message along with the session object.
Once I try to authenticate, req.session.user gives the output as 'undefined'. I referred several similar questions but couldn't solve my issue.How can I solve this issue?
Login function,
router.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
if (!email || !password) {
return res.status(400).json({ msg: "Please enter all fields" });
}
//Find user
User.findOne({ email : email })
.then(user => {
if(!user){
console.log('Not a user')
}
//Password matching
bcrypt.compare(password, user.password, (err, isMatch) => {
if(err) throw err;
if(isMatch){
console.log('Logged in')
const userSession = {
id: user.id,
name : user.name,
email : user.email
};
req.session.user = userSession;
res.json({ msg: "Logged in successfully", userSession});
} else {
console.log('Incorrect username or password')
}
});
})
.catch(err => console.log(err));
});
server.js,
const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const mongoose = require('mongoose');
const passport = require('passport');
const flash = require('connect-flash');
const session = require('express-session');
const cors = require('cors');
const MongoDBStore = require('connect-mongodb-session')(session);
const app = express();
const router = express.Router();
const {IS_PROD} = require('./config/config');
const MAX_AGE = 1000 * 60 * 2;
mongoose.connect("mongodb+srv://root:admin#cluster0-ynman.gcp.mongodb.net/test?retryWrites=true&w=majority", {useNewUrlParser:true, useCreateIndex:true, useUnifiedTopology:true})
.then(() => console.log('Mongo DB Connected'))
.catch(err => console.log(err));
//setting up connect-mongodb-session store
const mongoDBStore = new MongoDBStore({
uri: "mongodb+srv://root:admin#cluster0-ynman.gcp.mongodb.net/test?retryWrites=true&w=majority",
collection : "mySession"
})
//Bodyparser
app.use(express.urlencoded({extended:false}));
app.use(cors());
app.use(express.json());
//Express Session
app.use(session({
name: 'session',
secret: 'secret',
resave: true,
saveUninitialized: false,
store : mongoDBStore,
cookie :{
path : '/',
httpOnly: false,
maxAge : MAX_AGE,
sameSite: false,
secure : IS_PROD
}
}));
//Routes
app.use('/', require('./routes/index'));
app.use('/users', require('./routes/users'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server starts on port ${PORT}`));
Authenticate funtion,
router.get("/authenticator", (req, res) => {
const userSession = req.session.user;
console.log(userSession);
if(userSession){
return res.json({msg : "Authenticated successfully", userSession});
} else {
return res.status(401).json({msg : "Unauthorized"});
}
});

MongoDb and POSTMAN: Document isn't being added to collection

I am getting-started with mongodb.
I have set-up all the mongodb and the mongoose configuration and they work perfectly.
Here are the project files:
server.js:
const TableRow = require('./models/tableRow');
const bodyParser = require('body-parser');
const cors = require('cors')
const express = require('express');
const mongoose= require('mongoose')
const app = express();
const router = express.Router();
app.use(cors());
app.use(bodyParser.json());
mongoose.connect('mongodb://localhost/table', function(err) {
if (err) { throw err; }
console.log('Successfully connected');
});
const connection = mongoose.connection;
connection.on('error', console.error.bind(console, 'connection error:'));
connection.once('open', () => {
console.log('MongoDB database connection established successfully!');
});
app.use('/', router);
router.route('/table/add').post((req, res) => {
let tableRow = new TableRow (req.body);
tableRow.save()
.then(issue => {
res.status(200).json({'tableRow': 'Added successfully'});
})
.catch(err => {
res.status(400).send('Failed to create new record');
});
});
app.listen(5757, () => console.log(`Express server running on port 5757`));
tableRow.js
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
let TableRow = new Schema({
column1Data: {
type: String
},
column2Data: {
type: String
}
});
module.exports = mongoose.model('TableRow', TableRow);
When I tried testing this with POSTMAN:
I get this as you see in the response body:
{
"tableRow": "Added successfully" }
Since in server.js, I have this code:
router.route('/table/add').post((req, res) => {
let tableRow = new TableRow (req.body);
tableRow.save()
.then(issue => {
res.status(200).json({'tableRow': 'Added successfully'});
})
.catch(err => {
res.status(400).send('Failed to create new record');
});
});
I thought that should do the work. However when I type:
db.table.find()
I see that the table is empty. Any idea why?
Thank you!

How to use mockgoose (or any other db mocking) in express app integration test

Using mockgoose in a simple unit test is quite straight-forward. However I'm a bit fuzzy as to how one would go about using mockgoose or other mocking solutions in an acceptance or integration test.
Given a simple express/MongoDB app like the following:
/*app.js*/
const express = require('express')
const app = express()
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var greetingSchema = mongoose.Schema({
greeting: String
});
var Greeting = mongoose.model('Greeting', greetingSchema);
app.get('/', function (req, res) {
Greeting.find({greeting: 'Hello World!'}, function (err, greeting){
res.send(greeting);
});
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
and a simple integration test like this:
/*test.js*/
const app = require('app.js');
const request = require('supertest');
it('sends "Hello World!" on the response body', (done) => {
request(app)
.get('/')
.expect(200, 'Hello World!', done);
});
});
By using the actual app in the request, we are connecting to the app's database ('mongodb://localhost/test'). How then can one use mockgoose, or any other solution, to mock the MongoDB database and still run an integration test like the one shown above?
I had the same problem as you. In my case, I solved using chai + chai-http and breaking the db connection and app in different files:
db.js:
const mongoose = require('mongoose');
const config = require('../../config');
mongoose.Promise = global.Promise;
mongoose.set('debug', process.env.DEBUG != undefined);
function open(){
return new Promise((resolve, reject) => {
if(process.env.DEBUG != undefined) {
let Mockgoose = require('mockgoose').Mockgoose;
let mockgoose = new Mockgoose(mongoose);
mockgoose.helper.setDbVersion("** your mongodb version **");
mockgoose.prepareStorage().then(function() {
mongoose.connect(config.db_test, (err, res) => {
if (err) return reject(err);
resolve();
});
}).catch(reject);
}else{
mongoose.connect(config.db, (err, res) => {
if (err) return reject(err);
resolve();
});
}
});
}
function close(){
return mongoose.disconnect();
}
module.exports = { close, open };
app.js:
const express = require('express');
const bodyParser = require('body-parser');
const api = require('./routes');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use('/api', api);
module.exports = app;
test.js (for test):
const chai = require('chai');
const chaiHttp = require('chai-http');
const expect = chai.expect;
const conn = require('./../utils/db'); // <-- db.js
const app = require('../../app'); // <-- app.js
chai.use(chaiHttp);
describe('# Test', function(){
before(function(done) {
conn.open().then(() => done()).catch(done);
});
after(function(done){
conn.close().then(() => done()).catch(done);
});
it(`test something`, function(done){
chai.request(app) // <-- pass the app here
.get('/path/to/test')
.then((res) => {
// expects
done();
})
.catch((err) => {
done(err);
});
});
});
index.js (for development or production):
const conn = require('./utils/db'); // <-- db.js
const app = require('./app'); // <-- app.js
const config = require('./config');
conn.open().then(() => {
app.listen(config.port, () => {
// OK!
});
});
I hope it works for you or anyone.