I am chaining custom middleware function for my route handler in express but I am getting the above(title) error . Why is that?
Here is my code for middleware:
const Joi = require("joi");
function validateCredentials(req, res, next) {
const schema = {
email: Joi.string()
.max(1024)
.required()
.regex(/^([a-zA-Z0-9_\-\.]+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/),
password: Joi.string()
.min(6)
.max(255)
.required()
};
const result = Joi.validate({ email: req.body.email, password: req.body.password }, schema);
if(!result.error) {
return next();
}
}
module.exports.validateCredentials = validateCredentials ;
Here is route handler:
router.post('/api/signup', validateCredentials, passport.authenticate('local-signup'), (req, res) => {
const response = {};
response._id = req.user._id;
response.email = req.user.local.email;
res.send(response);
});
You are calling next only when validation passes not when there is an error.
Did you try this?
if (!result.error) {
return next();
} else {
return next(result.error);
}
Related
I need to Add a user I created this Auth.js File while hitting this endpoint from thunderclient the error must me catched and a res.json must be sent which is not happening what should i do:
Auth.js
const express=require('express');
const User = require('../models/User');
const router=express.Router();
const { body, validationResult } = require('express-validator');
router.post('/',[
body('email').isEmail(),
body('name').isLength({ min: 5 }),
body('password').isLength({ min: 5 })
], async (req, res)=>{
try{
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
User.create({
name: req.body.name,
password: req.body.password,
email: req.body.email
}).then(user => res.json(user));
}
catch(errors) {
console.error(errors)
res.json({error:'Please Use A Unique Value'})
}
})
module.exports = router
Since you're not making async operations in your router, express is ignoring errors returned from your router.post method as it is being treated as a promise.
You need to remove async keyword and make your route synchronous:
const express=require('express');
const User = require('../models/User');
const router=express.Router();
const { body, validationResult } = require('express-validator');
router.post('/',[
body('email').isEmail(),
body('name').isLength({ min: 5 }),
body('password').isLength({ min: 5 })
], (req, res)=>{ // removed async keyword
try{
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
User.create({
name: req.body.name,
password: req.body.password,
email: req.body.email
}).then(user => res.json(user));
}
catch(errors) {
console.error(errors)
res.json({error:'Please Use A Unique Value'})
}
})
when running the app and testing the /signup route the data gets written to the db and i can console.log it from the database/models.js file, but in the routes/index.js file it returns "Something went wrong." and postman shows nothing, not even an empty array or object.
routes/index.js
var express = require('express');
var router = express.Router();
const database = require('../database/models');
router.post('/signup', function(req, res, next) {
if (!req.body.email || !isValidEmail(req.body.email))
res.status(400).send('Email invalid.');
else if (!req.body.username || !isValidCredential(req.body.username) || !req.body.password || !isValidCredential(req.body.password))
res.status(400).send('Username/password invalid.');
else {
const result = database.createUser(req.body.email, req.body.username, req.body.password);
if (result)
res.status(200).send(result);
else
res.send('Something went wrong.');
}
});
function isValidEmail (email) {
if (email.match("[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"))
return true;
else
return false;
}
function isValidCredential (credential) {
if (credential.length < 6)
return false;
else if (credential.match(/^[a-z0-9]+$/i))
return true;
else
return false;
}
module.exports = router;
database/models.js
const tools = require('./tools');
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
email: String,
username: String,
hashedPassword: String,
salt: String,
accessToken: { type: String, default: "" }
});
const User = mongoose.model('User', userSchema);
function createUser(email, username, password) {
const hashPass = tools.generatePassword(password);
const newUser = new User({
email: email,
username: username,
hashedPassword: hashPass.hash,
salt: hashPass.salt
});
newUser.save(function (error, result) {
if (error)
return handleError(error);
return { email: result.email, username: result.username };
});
}
module.exports.createUser = createUser;
In your code you are not returning anything when calling the createUser function. Here a couple of considerations:
// index.js
const result = database.createUser(req.body.email, req.body.username, req.body.password);
since the createUser is an operation performed on a database, it will be probably asynchronous, and therefore also its result. I suggest the usage of async/await to be sure of the returned result. Also, you need to change the code of your models.js file to return a Promise and await for it.
function createUser(email, username, password) {
const hashPass = tools.generatePassword(password);
const newUser = new User({
email: email,
username: username,
hashedPassword: hashPass.hash,
salt: hashPass.salt
});
return new Promise((resolve, reject)=> {
newUser.save(function (error, result) {
if (error) reject(error);
resolve({ email: result.email, username: result.username });
});
});
}
and than you will have to await for your result. You can do it in the following way:
// index.js
// Add async here
router.post('/signup', async function(req, res, next) {
// ...other code
// Add await here
const result = await database.createUser(req.body.email, req.body.username, req.body.password);
I figured it out.
in routes/index.js use async/await like this:
router.post('/signup', async function(req, res, next) {
try {
if (!req.body.email || !isValidEmail(req.body.email))
res.status(400).send('Email invalid.');
else if (!req.body.username || !isValidCredential(req.body.username) || !req.body.password || !isValidCredential(req.body.password))
res.status(400).send('Username/password invalid.');
else {
const result = await database.createUser(req.body.email, req.body.username, req.body.password);
if (result)
res.status(200).send(result);
else
res.status(403).send(result);
}
} catch (error) { return error; }
});
and in database/models.js use async/await as well, but also rewrite mongoose methods into ones without callbacks, with returns into variables, like this:
async function createUser(email, username, password) {
try {
const hashPass = tools.generatePassword(password);
const newUser = new User({
email: email,
username: username,
hashedPassword: hashPass.hash,
salt: hashPass.salt
});
const result = await newUser.save();
return { email: result.email, username: result.username };
} catch (error) { console.log (error); return error; }
}
when I try to run the server, I get Route.get() requires callback functions but got a [object Undefined] error. If I comment out the router.post('/signup',validateRequest,isRequestValidated,signup)
everything works okay.
does anyone know what the problem might be and how to fix it?
router file:
const express = require('express');
const { signup, signin } = require('../controller/auth')
const {validateRequest,isRequestValidated} =require('../validators/auth')
const router = express.Router();
router.get('/signin', signin)
router.post('/signup',validateRequest,isRequestValidated,signup)
//Auth Guard
// router.post('/profile', requireSignin, (req, res) => {
// res.status(200).json({ user: 'profile' })
// })
module.exports = router;
validator file:
const { check, validationResult } = require('express-validator')
exports.validateSignUpRequest = [
check('firstName')
.notEmpty()
.withMessage('First Name is Required..!'),
check('lastName')
.notEmpty()
.withMessage('Last Name is Required..!'),
check('email')
.isEmail()
.withMessage('Plz Enter a Valid Email Address..'),
check('password')
.isLength({ min: 6 })
.withMessage('Password must be more than 6 characters')
];
exports.isRequestValidated = (req, res, next) => {
const errors = validationResult(req)
if (errors.array().length > 0) {
return res.status(400).json({ errors: errors.array()[0].msg })
}
next()
};
controller file :
const User = require('../models/user');
const jwt = require('jsonwebtoken');
const env = require('dotenv')
env.config()
// const {validationResult} = require('express-validator')
//SIGNUP:
exports.signup = (req, res) => {
User.findOne({ email: req.body.email })
.then((user) => {
if (user) {
res.status(400).json('User already exists')
}
else {
const _user = new User({
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
password: req.body.password,
username: Math.random().toString()
})
_user.save()
res.status(200).json(_user)
}
})
.catch((err) => {
res.status(500).json("Something Went Wrong")
})
}
change:
const {validateRequest,isRequestValidated} =require('../validators/auth')
to:
const {validateSignUpRequest,isRequestValidated} =require('../validators/auth')
and change:
router.post('/signup',validateRequest,isRequestValidated,signup)
to:
router.post('/signup',validateSignUpRequest,isRequestValidated,signup)
I am unable to write the correct query.
I am trying to check if the user already exists in the database and it will respond in Login Successfully Response.
This code is in working position problem lies in Query.
I hope somebody will help
function login() {
app.post("/login/", async(req, res) => {
const query = new Model({
email: req.body.email,
password: req.body.password,
});
const cursor = Model.find(query); // (*Here's the problem*)
console.log(cursor);
if (query === cursor) {**strong text**
console.log(query);
res.send("login successfully");
} else {
console.log(query);
res.send("user does not exist ");
}
});
}
login();
// Model and Schema
const LoginSchema = new mongoose.Schema({
email: { type: String, required: true },
password: { type: String, required: true },
});
const Model = mongoose.model("login_details", LoginSchema);
// Registeration Phase
function registration() {
app.post("/register/", async(req, res) => {
const model = new Model({
email: req.body.email,
password: req.body.password,
});
const result = await model.save();
console.log(result);
res.send(model);
});
}
// Headers
const express = require("express");
const app = express();
const mongoose = require("mongoose");
app.use(express.json());
app.use(express.urlencoded({ extend: true }));
//
Issues with your code
1- You don't need to use new Model({}) to query
2- You're using .find() which returns an array, use findOne() instead
3- You're attempting to check if a mongoose model (with _id) equals a query without the _id which won't work
4- Use return at the end of your function (won't affect the functionality here but just as good practice not to encounter errors like cannot set headers after they're sent)
possible solution
function login() {
app.post("/login/", async (req, res) => {
const cursor = await Model.findOne({
email: req.body.email,
password: req.body.password,
});
console.log(cursor);
if (cursor) {
console.log(cursor);
return res.send("login successfully");
} else {
return res.send("user does not exist ");
}
});
}
You are using Mongoose in the wrong way. Try this.
const result = await Model.find({
email: req.body.email,
password: req.body.password,
});
I am trying to make a register page with email and password.
I am having a problem with the post request.
Whenever I post through postman it keeps on sending requests.
and console shows promise pending.
function registration()
{
app.post('/login', (req, res) => {
const model = new Model({
email: req.body.email,
password: req.body.password
})
const result = model.save();
console.log(result);
})
}
registration();```
//here's the remaing portion
`
const express = require('express');
const app = express();
app.use(express.json());
const mongoose = require('mongoose');
const port = process.env.port || 3000;
app.listen(port, () => console.log(`listening to port ${port}`));
mongoose.connect("mongodb://localhost:27017/Login", { useNewUrlParser: true, useUnifiedTopology: true })
.then(()=>console.log('connected mfs'))
.catch((err) => console.error("error found...", err));
const LoginSchema = new mongoose.Schema({
email:{type:String, required: true},
password:{type:String, required :true}
});
const Model = mongoose.model('login', LoginSchema);
The .save() function returns a promise
possible solutions
1- use async/await
function registration() {
app.post('/login', async (req, res) => {
const model = new Model({
email: req.body.email,
password: req.body.password
})
const result = await model.save();
console.log(result);
})
}
2- use promises
function registration() {
app.post('/login', (req, res) => {
const model = new Model({
email: req.body.email,
password: req.body.password
})
model.save().then(result => console.log(result))
})
}
3- use callbacks (don't recommend that though)
Also you can use .create() instead of new Model({}) and then model.save()
like this
1- async/await
function registration() {
app.post('/login', async (req, res) => {
const model = await Model.create({
email: req.body.email,
password: req.body.password
})
console.log(model)
})
}
2- promises
function registration() {
app.post('/login', (req, res) => {
Model.create({
email: req.body.email,
password: req.body.password
})
.then(model => console.log(model))
})
}