App is getting crashed on duplicate response, Error is not catched - node.js

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'})
}
})

Related

JWT token signup and signin express API

I am trying postman for signup a user, {"firstName": "John", "lastName":"zoe", "email":"aaa#gmail.com", "password":"123465"} but the postman gives me this 500 error: {
"message": "Something went wrong"
},
I could not figure out is my logic wrong, or something is missing, I did not use the validator package, as I am not sure how to use it, is that the problem? can anyone pls help?
here is my code, in the server.js file:
const express = require("express");
const env = require("dotenv");
const { response } = require("express");
const app = express();
const mongoose = require("mongoose");
//routes
const authRoutes = require("./routes/auth");
const adminRoutes = require("./routes/adminauth");
const categoryRoutes = require("./routes/category");
//enviorment variables
env.config();
app.use(express.json());
mongoose
.connect(
`mongodb+srv://${process.env.MONGO_DB_USER}:${process.env.MONGO_DB_PASSWORD}#cluster0.h28xczp.mongodb.net/${process.env.MONGODB_DATABASE}?retryWrites=true&w=majority`
)
.then(() => {
console.log("Database connection established");
});
app.use("/api", authRoutes);
app.use("/api", adminRoutes);
app.use("/api", categoryRoutes);
app.listen(process.env.PORT, () => {
console.log(`server is running at ${process.env.PORT}`);
});
In my routes file:
const express = require("express");
const router = express.Router();
const { signupUser, loginUser } = require("../controller/auth");
const { auth, userMiddleware, adminMiddleware } = require("../middleware/auth");
//login route
router.post("/login", loginUser);
//signup route
router.post("/signup", signupUser);
module.exports = router;
Middleware file:
const jwt = require("jsonwebtoken");
const User = require("../models/user");
exports.auth = (req, res, next) => {
try {
const token = req.header.authorization.split("")[1];
const isCustomAuth = token.length < 500;
let decodeData;
if (token && isCustomAuth) {
decodeData = jwt.verify(token, env.Process.JWT_SECRET);
req.UserId = decodeData?.id;
} else {
decodeData = jwt.decode(token);
req.UserId = decodeData?.sub;
}
next();
} catch (error) {}
};
exports.userMiddleware = (req, res, next) => {
if (req.user.role !== "user") {
return res.status(400).json({ message: "User access denied" });
}
next();
};
exports.adminMiddleware = (req, res, next) => {
if (req.user.role !== "admin") {
return res.status(400).json({ message: "Access denied" });
}
next();
};
In my controller file:
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
exports.loginUser = async (req, res) => {
const { email, password } = req.body;
try {
const existingUser = await User.findOne({ email });
if (!existingUser)
return res.status(400).json({ message: "User does not exists." });
const isPasswordCorrect = await bcrypt.compare(
password,
existingUser.password
);
if (!isPasswordCorrect)
return res.status(400).json({ message: "Invalid credentials." });
const token = jwt.sign(
{ email: existingUser.email, id: existingUser._id },
process.env.JWT_SECRET,
{ expiresIn: "3d" }
);
res.status(200).json({ result: existingUser, token });
} catch (error) {
res.status(500).json({ message: "Something went wrong" });
}
};
exports.signupUser = async (req, res) => {
const { firstName, lastName, email, password, confirmPassword } = req.body;
try {
const existingUser = await User.findOne({ email });
if (existingUser)
return res.status(400).json({ message: "User already exists." });
if (!password == confirmPassword)
return res.status(400).json({ message: "Password don't match" });
const hashedPassword = await bcrypt.hash(password, 12);
const result = await User.create({
email,
password: hashedPassword,
firstName,
lastName,
});
const token = jwt.sign(
{ email: result.email, id: result._id },
process.env.JWT_SECRET,
{ expiresIn: "3d" }
);
res.status(200).json({ result, token });
} catch (error) {
res.status(500).json({ message: "Something went wrong" });
}
};
My user model file:
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const userSchema = new mongoose.Schema(
{
firstName: {
type: String,
required: true,
trim: true,
},
lastName: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
},
password: {
type: String,
required: true,
},
id: {
type: String,
},
},
{ timestamps: true }
);
module.exports = mongoose.model("User", userSchema);
In the middleware, this line contains a wrong reference to JWT_SECRET.
decodeData = jwt.verify(token, env.Process.JWT_SECRET);
Should be
decodeData = jwt.verify(token, process.env.JWT_SECRET);
The application throws an unhandled promise rejection error when trying to connect DB, which means it can operate without a DB connection and then throw that error.
So, to handle that, you can rewrite your code to this.
mongoose.connect('mongodb://localhost:27017/usersdb', // change with your db url
{
useNewUrlParser: true,
useUnifiedTopology: true
}
)
.then(() => {
app.use("/api", authRoutes);
app.listen(process.env.PORT, () => {
console.log("Server has started on port!", process.env.PORT)
})
})
.catch(() => { throw new Error(("Connection error")) });
Also, I successfully ran and tested your application on my local machine. Here is a GitHub link; you can compare.
https://github.com/nairi-abgaryan/express-auth

Error: Route.post() requires a callback function but got a [object Undefined] throw new Error(msg);

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 getting this error TypeError: Cannot read properties of undefined (reading 'header') , I am trying to middleware to get users data

I have created a middleware folder inside it I have created fetchuser.js
This is my fetchuser.js code, I have created getuser endpoint so that I can authenticate the user.
I have created a new post request in my thunderclient, but because of this error I am not able to do anything
...
const jwt = require('jsonwebtoken');
const JWT_SECRET = "Saurabhisgood$ouy";
const fetchuser = (req, res, next) => {
// Get the user from jwt token and id to req object
const token = req.header('auth-token');
if (!token) {
res.status(401).send({ error: "Please authenticate using a valid token" })
}
try {
const data = jwt.verify(token, JWT_SECRET)
req.user = data.user;
next();
} catch (error) {
res.status(401).send({ error: "Please authenticate using a valid token" })
}
}
module.exports = fetchuser();
...
This is auth.js file
...
const express = require('express');
const User = require('../models/User');
const router = express.Router();
const { body, validationResult } = require('express-validator');
const bcrypt = require('bcryptjs');
const JWT_SECRET = "Saurabhisgood$ouy";
const jwt = require('jsonwebtoken');
const fetchuser = require('../middleware/fetchuser');
// Create a user using : POST "/api/auth/createuser". Doesn't require auth. Dosen't require login
router.post('/createuser', [
body('name', 'Name should be atleast 3 characters').isLength({ min: 3 }),
body('email', 'Email should be unique').isEmail(),
body('password', 'Password must be atleast 5 characters').isLength({ min: 5 }),
], async (req, res) => {
// If there are errors then you will get bad request
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Check whether the user with the same email exists
try {
let user = await User.findOne({ email: req.body.email });
if (user) {
return res.status(400).json({ error: "The user with this email already exists" })
}
const salt = await bcrypt.genSalt(10);
const secPass = await bcrypt.hash(req.body.password, salt);
// Create a new user
user = await User.create({
name: req.body.name,
email: req.body.email,
password: secPass
});
const data = {
user: {
id: user.id
}
}
const authToken = jwt.sign(data, JWT_SECRET);
// console.log(jwtData);
// res.json(user);
res.json({authToken});
} catch (error) {
console.error(error.message);
res.status(500).send("Internal server error")
}
})
// Authenticate a user using : POST "/api/auth/login". Doesn't require auth. Dosen't require login
router.post('/login', [
body('email', 'Email should be unique').isEmail(),
body('password', 'Password cannot be blank').exists(),
], async (req, res) => {
// If there are errors then you will get bad request
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
};
const { email, password } = req.body;
// Check whether the user with the same email exists
try {
let user = await User.findOne({email});
if (!user) {
return res.status(400).json({ error: "Please enter the valid credentials" })
}
const passwordComapare= await bcrypt.compare(password, user.password);
if (!passwordComapare) {
return res.status(400).json({ error: "Please enter the valid credentials" })
}
const data = {
user: {
id: user.id
}
}
const authToken = jwt.sign(data, JWT_SECRET);
// console.log(jwtData);
// res.json(user);
res.json({authToken});
} catch (error) {
console.error(error.message);
res.status(500).send("Internal server error")
}
})
// Get details of logged in user using : POST "/api/auth/getuser". Require login
router.post('/getuser', fetchuser , async (req, res) => {
try {
userId= req.user.id;
const user= await User.findById(userId).select("-password");
res.send(user);
} catch (error) {
console.error(error.message);
res.status(500).send("Internal server error")
}
})
module.exports = router
...
You invoking the middleware automatically, change:
module.exports = fetchuser();
to:
module.exports = fetchuser;

errors generated by express validator with node express [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I am using nodejs, express, & express-validator. I am trying to use express validator on my sign_up page . Express-validator generates the errors in an array of objects.
the error:
Result {
formatter: [Function: formatter],
errors: [
{
value: undefined,
msg: 'Please Enter a Valid Username',
param: 'username',
location: 'body'
},
{
value: undefined,
msg: 'Please enter a valid email',
param: 'email',
location: 'body'
},
{
value: undefined,
msg: 'Please enter a valid password',
param: 'password',
location: 'body'
}
]
}
I use postman to test the register operation
and send the following in the request:
{
"username":"ruba",
"email":"test#gmail.com",
"password":"1234544545#"
}
my user.js code:
// Filename : user.js
const express = require("express");
const { check, validationResult} = require("express-validator");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const router = express.Router();
const User = require("../model/User");
/**
* #method - POST
* #param - /signup
* #description - User SignUp
*/
router.post(
"/signup",
[
check("username", "Please Enter a Valid Username")
.not()
.isEmpty(),
check("email", "Please enter a valid email").isEmail(),
check("password", "Please enter a valid password").isLength({
min: 6
})
],
async (req, res) => {
const errors = validationResult(req);
console.log(errors);
if (!errors.isEmpty()) {
console.log("error sign");
return res.status(400).json({
errors: errors.array()
});
console.log("error sign2");
}
console.log("error sign3");
const {
username,
email,
password
} = req.body;
try {
let user = await User.findOne({
email
});
if (user) {
return res.status(400).json({
msg: "User Already Exists"
});
}
user = new User({
username,
email,
password
});
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
await user.save();
const payload = {
user: {
id: user.id
}
};
jwt.sign(
payload,
"randomString", {
expiresIn: 10000
},
(err, token) => {
if (err) throw err;
res.status(200).json({
token
});
}
);
} catch (err) {
console.log(err.message);
res.status(500).send("Error in Saving");
}
}
);
module.exports = router;
my index code:
const express = require("express");
const bodyParser = require("body-parser");
const user = require("./routes/user"); //new addition
const InitiateMongoServer = require("./config/db");
// Initiate Mongo Server
InitiateMongoServer();
const app = express();
// PORT
const PORT = process.env.PORT || 4000;
// Middleware
//app.use(bodyParser.json());
app.use(express.json());
app.get("/", (req, res) => {
res.json({ message: "API Working" });
});
app.use("/user", user);
app.listen(PORT, (req, res) => {
console.log(`Server Started at PORT ${PORT}`);
});
so please help me. what is the problem??
Edit: It's solved. the problem was in the postman settings (the contents type must be JSON)
Did you enabled
app.use(express.json());
Because I cant see any kind of problem with you code (about the express-validator).
I suggest you after this fix, you to change check to body since you wants only to check the content of body.
I'm using an middleware to helps to me keep my code short and legible, and I'll share with you
function validation(validations: Array<ValidationChain>) {
return async (req: Request, _res: Response, next: NextFunction) => {
await Promise.all(validations.map((v) => v.run(req)));
const errors = validationResult(req);
if (errors.isEmpty()) {
return next();
}
const msg = errors
.array()
.map((er) => `${er.param}`)
.join(', ');
const issue = new Issue(400, `missing or invalid params: ${msg}`);
next(issue);
};
}
The usage:
router.post(
'/login',
validation([body('email').isEmail(), body('password').isLength({ min: 5, max: 30 })]),
async (req: Request, res: Response, next: NextFunction): Promise<void> => {
...
});
``'

Route.post() requires a callback function but got a [object Object]

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);
}

Resources