I'm currently part of a web dev Bootcamp and my current project is requesting I create error handlers in a specific manner that I do not understand. Below is a screenshot of the directions . . .
Here are my current files in hopes that it makes sense . . .
/* app.js */
const express = require('express');
const mongoose = require('mongoose');
const userRouter = require('./routes/users');
const cardRouter = require('./routes/cards');
const { PORT = 3000 } = process.env;
const app = express();
mongoose.connect('mongodb://localhost:27017/aroundb', {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
useUnifiedTopology: true,
});
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use((req, res, next) => {
req.user = { _id: '60c4e0e2a80be4c8c2de5474' };
next();
});
app.use('/users', userRouter);
app.use('/cards', cardRouter);
app.listen(PORT, () => logMsg(`listening on port ${PORT} . . .`));
/* routes/users.js */
const express = require('express');
const { getUsers, getUser, createUser } = require('../controllers/users');
const router = express.Router();
router.get('/', getUsers);
router.get('/:id', getUser);
router.post('/', createUser);
module.exports = router;
/* controllers/users.js */
const User = require('../models/user');
module.exports.getUsers = (req, res) => {
User.find({})
.then((users) => res.status(200).send({ data: users }))
.catch((err) => res.status(500).send({ message: err }));
};
module.exports.getUser = (req, res, next) => {
User.findById(req.params.id)
.then((user) => res.send({ data: user }))
.catch((err) => res.status(404).send({ message: err }));
};
module.exports.createUser = (req, res) => {
const { name, about, avatar } = req.body;
User.create({ name, about, avatar })
.then((user) => res.status(201).send({ data: user }))
.catch((err) => res.status(400).send({ message: err }));
};
My questions are:
Where should the code example provided (in the screenshot) go? Am I creating a separate controller or middleware? Or maybe it goes in the already coded controller?
Would I be creating my own errors and using a conditional to read the message?
I already thought I was handling errors, as seen in controllers/users.js, is that not the case?
NOTE: My apologies, I know that since it's from a course it might not make sense outside the context of the lesson(s). I also know there are various ways projects can be coded/solved. Unfortunately, my Bootcamp does not have live instruction, just a slack channel where 97% of responses come from Alumni. Please do not hesitate to ask questions that may help clarify things.
It seems you're directly sending an error in the last two cases, without knowing which type of it is, however it looks fine for fetching all users (1st case).
The workaround that might help you is,
Get user :
User.findById(req.params.id), function(err, user) {
if(err) {
return res.status(500).send({ message: "Default error" });
} else if (!user) {
return res.status(404).send({ message: "User not found" });
}
}
For creating a user you need to manually verify all the fields that are required in schema for ex.,
createUsers : {
const { name, about, avatar } = req.body;
if (name === null || about === null || avatar === null) {
return res.status(400).send({
message : "Required data missing in request"
})
}
... // create user
}
Related
Hello I am super new to web development, currently doing the udemy bootcamp. I was working on my app and everything was fine but suddenly my browser stopped rendering and I got this error:
VM10:6747 crbug/1173575, non-JS module files deprecated.
Got the error even though it shows in my terminal that the database is connected and working. I googled and youtubed this problem but none of the solutions online seem to work. I am using VSC and I went ahead and deleted the launch.json file but that didnt work either. Any other suggestions would really be appreciated. Is there anything within my code that can produce this error? Here is my app.js in case I am missing something.
const express = require('express');
const path = require('path');
const mongoose = require('mongoose');
const ejsMate = require('ejs-mate'); //this is an engine use to parse ejs
const session = require('express-session');
const flash = require('connect-flash');
const ExpressError = require('./utils/ExpressError');
const methodOverride = require('method-override');
//requiring routes
const campgrounds = require('./routes/campgrounds');
const reviews = require('./routes/reviews');
mongoose.set('strictQuery', true);
mongoose.connect('mongodb://127.0.0.1:27017/yelp-camp', { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
console.log("Database connected")
})
.catch(err => {
console.log("Database not connected")
console.log(err)
});
const app = express();
app.engine('ejs', ejsMate); //here we are telling express to use the engine we selected instead of the default one
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.urlencoded({ extended: true })); //to help us parse the req.body
app.use(methodOverride('_method'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(flash);
const sessionConfig = {
secret: 'thisshouldbeabettersecret',
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true, //this is a security item
expires: Date.now() + 1000 * 60 * 60 * 24 * 7, //date.now is in miliseconds. the numbers after are a multiplication = to a week
maxAge: 1000 * 60 * 60 * 24 * 7
}
}
app.use(session(sessionConfig));
app.use((req, res, next) => {
res.locals.success = req.flash('success');
res.locals.error = req.flash('error');
next();
});
app.use('/campgrounds', campgrounds);
app.use('/campgrounds/:id/reviews', reviews);
app.get('/app', (req, res) => {
// res.send('hello! working on your request')
res.render('home')
})
// HOME PAGE
app.get('/', (req, res) => {
res.send('HOMEPAGE!');
})
//ERROR MIDDLEWARE
app.all('*', (req, res, next) => {
next(new ExpressError('Page not found', 404))
}) //this selects all and if nothing else wrongs this will.
app.use((err, req, res, next) => {
const { statusCode = 500 } = err; //here we are deconstructing our expresserror and then sending the message
if (!err.message) err.message = 'Oh no, Something Went Wrong';
res.status(statusCode).render('error', { err })
})
app.listen(3000, () => {
console.log("Serving in port 3000")
})
Nevermind! Found the error.
Had:
app.use(flash)
Instead of:
app.use(flash())
I am using the relatively newer setup with Next.js API routes, this doesn't use express but instead the API setup to create your routes to an endpoint.
My problem is I'd like to have a route called api/user which will return the user i.e. req.user:
The following comes from with-passport-and-next-connect
import nextConnect from 'next-connect'
import auth from '../../middleware/auth'
const handler = nextConnect()
handler
.use(auth)
.get((req, res) => {
if (req.session.user) {
const { _id } = req.session.user
res.json({ user: { _id } })
} else {
res.json({ user: null })
}
})
export default handler
That file references this auth file:
import nextConnect from 'next-connect'
import passport from '../lib/passport'
import session from '../lib/session'
const auth = nextConnect()
.use(
session({
name: 'sess',
secret: process.env.TOKEN_SECRET,
cookie: {
maxAge: 60 * 60 * 8, // 8 hours,
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
path: '/',
sameSite: 'lax',
},
})
)
.use((req, res, next) => {
// Initialize mocked database
// Remove this after you add your own database
req.session.users = req.session.users || []
next()
})
.use(passport.initialize())
.use(passport.session())
export default auth
I have added this in my version:
.use((req, res, next) => {
connectDB()
next()
})
But that yields nothing.
In api/login I added this line
req.session.user = req.user;
after the authenticate function. But that doesn’t add the user to the session object.
handler
.use(auth)
.post((req, res, next) => {
emailValidator(req, res, next, 'email', 'password');
},
async (req, res, next) => {
await connectDB();
passport.authenticate('local', (err, user, info) => {
req.session.user = req.user;
Could anyone please help me with this?
Thanks in advance.
I want to use socekt.io for a new project I am building. I am using socket.io for a login component and will be using socket.io in the future to update pages like a chat app. I am also using mongoose to handle my mongodb connection. I am taking in a username, and returning a password to my front end to be bcryptjs compareSync hashed. The problem I am having is that whatever is returned to the front end is undefined. When I print out what is returned to the front end, it prints out the value I am looking for though. Something is going on between the backend emitting something, and the frontend receiving something but I don't know what is it exactly. Here is my code for the back end:
const express = require('express')
const socket = require('socket.io');
const http = require('http');
const router = require('./router');
const mongoose = require('mongoose');
let Player = require('../models/player.model');
require('dotenv').config();
const PORT = process.env.PORT || 5000;
const app = express();
const server = http.createServer(app);
const uri = process.env.ATLAS_URI;
mongoose.connect(uri, {useNewUrlParser: true, useCreateIndex: true,
useUnifiedTopology: true });
const connection = mongoose.connection;
connection.once('open',() => {
console.log('MongoDB database connection established successfully')
});
const io = socket(server);
io.on('connection', (socket) => {
console.log('We have a new connection');
socket.on('login', ({ username }, callback) => {
console.log(username);
Player.find({"username": username}, function (err, player) {
if(err) {
console.log("there has been an error"), {player: null}
}
socket.emit('id', { password: player[0]['password'].toString(), id : player[0]['_id']})
}) })})
app.use(router);
server.listen(PORT, () => console.log('Server is working'))
Here is my code for the front end:
const ENDPOINT = 'localhost:5000';
async function submitAccount (e) {
e.preventDefault();
socket.emit('login', { username });
socket.on("id", (response) => {
setPassword2(String(response['password']));
id = response['id']; console.log(id);
console.log(password2)
});
try {
if (bcrypt.compareSync(password, password2) == true) {
props.setCookie("id", id);
setAccess(true);
access2 = true;
console.log(access2)
console.log('works')
}
else {
setErrorType('Invalid Password')
setErrorMsg('There is an issue with your password. Please try again')
setOpenModal(true)
console.log(password);
console.log(password2);
}
}
catch {
setErrorType('Invalid Username')
setErrorMsg('This username does not exist. Please try another')
setOpenModal(true)
}
Thanks for the help!
When you do the socket.on, it should include the whole statement you are looking to change with the socket.io output. See below:
async function submitAccount (e) {
e.preventDefault();
socket.emit('login', { username });
socket.on("id", (response) => {
setPassword2(String(response['password']));
id = response['id']; console.log(id);
console.log(password2)
if (password2 != undefined) {
try {
if (bcrypt.compareSync(password, password2) == true) {
props.setCookie("id", id);
setAccess(true);
access2 = true;
console.log(access2)
console.log('works')
}
}
I'm writing an a async function with ES6 promises, that 1) saves the query parameters for a user 2) fetches data from mongodb using mongoose, 3) manipulates the json into a DSL, 4) and queries another db with it.
mongoose": "^4.7.7"
//myController.js
const myQuery = require('../models/myQuery_model');
require('mongoose').Promise = global.Promise
const uuidV4 = require('uuid/v4');
exports.saveNewQuery = function(req, res, next) {
const rawQuery = req.body;
const queryToStore = new myQuery(rawQuery);
const uid = uuidV4();
const queryToStore.uid = uid
queryToStore.save().then(() => {
fetchQueryFromMongo(uid);
}).then((storedQuery) => {
compileQueryToString(storedQuery);
}).then((queryString) => {
fetchResultsFromOtherDb(queryString);
}).then((results) => {
res.json({ results });
}).catch((error) => {
console.log(error)
})
}
Currently I'm not able to resolve the response from mongodb step 2. Still, the controllter goes on to compileQueryToString rather than catch the error from fetchQueryFromMongo
// fetchQueryFromMongo.js
const myQuery = require('../models/myQuery');
require('mongoose').Promise = global.Promise
module.exports = (uid) => {
return new Promise(
(resolve, reject) => {
myQuery.find({ uid }).then((err, res) => {
if (err) {
reject(err);
}
console.log('response success!')
resolve(res);
});
}
);
};
I'm new to promises so any tips / suggestions would be appreciated!
Make sure to return a value from your then handlers. The code below does this by using the concise body form of arrow functions.
queryToStore.save()
.then(() => fetchQueryFromMongo(uid))
.then(storedQuery => compileQueryToString(storedQuery))
.then(queryString => fetchResultsFromOtherDb(queryString))
.then(results => res.json({ results }))
.catch(console.log);
I have had many problems, when I want to get information from user model. I read some solutions, but I didnt understand.
This is my code:
* AuthController
var passport = require('passport');
module.exports = {
_config: {
actions: false,
shortcuts: false,
rest: false
},
login: function(req, res) {
passport.authenticate('local', function(err, user, info) {
if ((err) || (!user)) {
return res.send({
message: info.message,
user: user
});
}
req.logIn(user, function(err) {
if (err) res.send(err);
return res.send({
message: info.message,
user: user
});
});
})(req, res);
},
logout: function(req, res) {
req.logout();
res.redirect('/');
},
signup: function (req, res) {
var data = req.allParams();
User.create({email:data.email,password:data.password,name:data.name}).exec(function(error,user){
if(error) return res.negotiate(err);
if(!user)return res.negotiate(err);
return res.ok();
});
}
};
*view
<h1>List of my dates</h1>
<h1><%= email %></h1>
<h1><%= req.user.name %></h1>
*model
attributes: {
email: {
type: 'email',
required: true,
unique: true
},
password: {
type: 'string',
minLength: 6,
required: true
},
toJSON: function() {
var obj = this.toObject();
delete obj.password;
return obj;
}
},
beforeCreate: function(user, cb) {
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {
console.log(err);
cb(err);
} else {
user.password = hash;
cb();
}
});
});
}
};
Only works if I use res.render('view', {email: req.user.email}) but, I would like to use the user data in many views. I cant write methods with Current user params, becouse dont work.
Thanks.
It is unclear to me what your actual problem is or what the question actually is but I will try to help.
Look here:
login: function(req, res) {
passport.authenticate('local', function(err, user, info) {
if ((err) || (!user)) {
return res.send({
message: info.message,
user: user
});
}
...
})(req, res);
},
There you are adding data (locals) to the ejs and the values are message and user so in the ejs you must reference it as this, so you will use user.name and not req.user.name? I'm not sure why you're binding the (req, res) either.
It's confusing because your ejs uses the email value but I don't see it there as a local so maybe thats your problem, it must be defined?
Consider the following simple example:
// User Controller
// GET request /signin
// The signin form
signin(req, res) {
// Load the view from app/views/*
return res.view('signin', {
title: 'Sign In'
});
},
// POST request to /signin
// This was posted from the signin form
// Use io.socket.post(...) to do this from the signin form
// Can use window.location.replace('/account') on successful request
authenticate(req, res) {
// The data posted, email and password attempt
var data = req.allParams();
// Does it match?
User.findOne({
email: data.email,
// This is stupid, don't ever use plain text passwords
password: data.password
})
.exec(function(err, user) {
// Server related error?
if (err) res.serverError(err.message);
// No user was found
if (!user) res.badRequest('Username or password not found');
// Sign the user in
req.session.userId = user.id;
// User was found
res.ok();
});
},
// GET request to /account
// Displays the users information
// Can use policies to ensure that only an authenticated user may access their own account information
account(req, res) {
// If the user is not signed in
// This is an alternative to using the sails policy isLoggedIn
if (!req.session.userId) res.redirect('/signin');
// Get the users details
User.findOne({
id: req.session.userId
})
.exec(function(err, user) {
// Server related error?
if (err) res.serverError(err.message);
// No user was found
if (!user) res.redirect('/signin');
// Load the ejs file that displays the users information
return res.view('account/index', {
title: 'Account Information',
user: user
});
});
},
// Account View
<p>Email: {{user.email}}</p>
<p>Password: {{user.password}}</p>
Check this out if you want to deal with password encryption: http://node-machine.org/machinepack-passwords
And this if you want to deal with the strength tests (when the user sets the password): https://www.npmjs.com/package/owasp-password-strength-test
This is as passport seems overkill if you're only doing local authentication?