I can't get a response from my server. I am using postman and running the following post request:
localhost:4000/users/register?email=test#gmail.com&f_name=testf&s_name=tests&password=test
It hangs for a very long time and then says:
Could not get any response
This is my code:
[user.route.js]
const express = require('express');
const userRoutes = express.Router();
const cors = require('cors');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
//require User model in the routes module
let User = require('../models/user.model.js');
//Make router use cors to avoid cross origin errors
userRoutes.use(cors);
//secret
process.env.SECRET_KEY = 'secret';
//define register route
userRoutes.post('/register', (req, res) => {
const today = new Date();
const userData = {
email: req.body.email,
f_name: req.body.f_name,
s_name: req.body.s_name,
password: req.body.password,
created: today
}
//Find one user based on email, hash their password and then create a document in the collection for that user
User.findOne({
email: req.body.email
})
.then(user => {
if (!user) {
bcrypt.hash(req.body.password, 10, (err, hash) => {
user.password = hash;
User.create(userData)
.then(user => {
res.json({
status: user.email + ' registered'
});
})
.catch(err => {
res.send('error: ' + err);
});
});
}
});
});
userRoutes.post('/login', (req, res) => {
User.findOne({
email: req.body.email
})
.then(user => {
if (user) {
if (bcrypt.compareSync(req.body.password, user.password)) {
const payload = {
_id: user._id,
f_name: user.f_name,
s_name: user.s_name,
email: user.email
}
let token = jwt.sign(payload, process.env.SECRET_KEY, {
expiresIn: 1440
});
res.send(token);
} else {
res.json({
'Error': 'Password Incorrect'
});
}
} else {
res.json({
'Error': 'User does not exist'
});
}
})
.catch(err => {
res.send('Error: ' + err);
});
});
module.exports = userRoutes;
[user.model.js]
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let User = new Schema({
email: {
type: String
},
f_name: {
type: String
},
s_name: {
type: String
},
password: {
type: String
},
created: {
type: String
}
}, {
collection: 'users'
});
[server.js]
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const PORT = 4000;
const cors = require('cors');
const mongoose = require('mongoose');
const config = require('./db.js');
mongoose.Promise = global.Promise;
mongoose.connect(config.DB, {
useNewUrlParser: true
}).then(
() => {
console.log('Database is connected')
},
err => {
console.log('Can not connect to the database' + err)
}
);
app.use(cors());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
var Users = require('./routes/user.route');
//make /users use routes
app.use('/users', Users);
app.listen(PORT, function() {
console.log('Server is running on Port:', PORT);
});
[db.js]
module.exports = {
DB: 'mongodb://localhost:27017/pharaohcrud'
}
I'm using Node, MongoDB, Mongoose, Vue, Express.
I'm new to Node in general so it's hard for me to give details on what i've done. Please feel free to ask any questions that you need answered to help me with issue and ill answer as thoroughly as i can :)
EDITS:
Here is the updated db.js file
module.exports = {
DB: 'mongodb://localhost:27017/pharaoh'
}
Here is the updated post request that im sending to the server through postman:
localhost:4000/users/register
[raw json request]
{
"email": "test#gmail.com",
"f_name": "test",
"s_name": "test",
"password": "test"
}
You have to send json data with your post request not query strings.
In postman, select "Body" tab and choose "raw" and from the dropdown menu select "json" format. Send your user data as Json, this will solve the issue.
Image description here
I went deleted all database-related code and retyped it, and now it works. I guess the lesson here is to always pay attention while typing code to make sure you're writing it correctly.
Related
Below is the sign up controller...
const signup = async (req, res) => {
const { name, username, profilePhoto, email, password } = req.body;
console.log(req.body);
try {
const existingUser = await User.findOne({ email });
if (existingUser)
return res.status(404).json({ message: "User already exist." });
const hashedPassword = await bcrypt.hash(password, 12);
const result = await User.create({
name,
username,
email,
profilePhoto,
password: hashedPassword,
});
const token = jwt.sign(
{
name: result.name,
email: result.email,
username: result.username,
id: result._id,
},
"test",
{
expiresIn: "1h",
}
);
res.status(200).json({ result: result, token });
} catch (error) {
res.status(500).json({ message: "Something went wrong" });
}
};
This is the code for action for SignUp
export const signup = (formData, history) => async (dispatch) => {
try {
// sign up the user
const { data } = await api.signUp(formData);
dispatch({ type: "AUTH", data });
toast.success("Signed Up successfully");
history.push("/feedbacks");
} catch (error) {
dispatch({ type: "ERROR", data: error?.response?.data });
toast.error(error?.response?.data?.message);
}
While signing in I am getting proper response on the console in the backend. But unable to SignUp.
Error:
But the output of console has the response:
Other functionalities are also working in sync with Front-End
routes
Index.js
const express = require("express");
const connectDB = require("./config/db");
const cors = require("cors");
const app = express();
const feedbacksRoutes = require("./routes/feedbacks");
const userRoutes = require("./routes/users");
app.use(express.json({ extended: false }));
app.use(cors());
// connect to mongoDB
connectDB();
app.use("/feedbacks", feedbacksRoutes);
app.use("/user", userRoutes);
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
I was trying to set up a email verification method using nodemailer but it seems to not work for some reason. Can anyone find a fix ?
i will first generate the token and then send it to the user for them to verify their email and continue login process. I seem to be stuck in this part. Node mailer not sending the email but user registration info does save in the database.
my register route -
const User = require('../models/User');
const router = require('express').Router();
const bcrypt = require('bcrypt');
const mongoose = require('mongoose');
const nodemailer = require('nodemailer');
const Token = require('../models/token');
router.post('/register', async (req,res) => {
try {
user = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password
});
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(user.password, salt);
// create and save user
await user.save(function(err) {
if (err) {
return res.status(500).send({msg: err.message});
}
});
// genereate token and save
let token = new Token({_userId: user._id, token: crypto.getRandomValues(16).toString('hex')});
token.save(() => {
if(err) {
return res.status(500).send({msg: err.message});
}
let transporter = nodemailer.createTransport({service: 'gmail', auth: {user: 'myEmail', pass: "Password"}});
let mailOptions = {from: "authmail14#gmail.com", to: user.email, subject: "Account Verification Link"}
transporter.sendMail(mailOptions, function(err) {
if(err) {
return res.status(500).send({msg: "Technical Issue"})
}
return res.status(200).send('Email Sent')
})
});
} catch {
console.log("NO result")
}
});
module.exports = router;
tokenSchema -
const mongoose = require("mongoose");
const tokenSchema = new mongoose.Schema({
_userId: {type: mongoose.Schema.Types.ObjectId, required: true, ref: "user"},
token: {type: String, required: true},
expiredAt: {type: Date, default: Date.now(), index: {expires: 86400000}}
});
const token = mongoose.model('token', tokenSchema);
module.exports = token;
userSchema -
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: {
type: String, required: true, minlength: 5,maxlength:30
},
email: {
type: String, unique:true, maxlength:30
},
password: {
type: String, minlength: 8, required:true
},
isAdmin: {
type: Boolean, default: false
},
createdAt: {
type: Date, default: Date.now
},
verified: {
type: Boolean, default: false
}
});
app.js -
const express = require('express');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const path = require('path');
const authRoute = require('./routes/auth');
dotenv.config();
const app = express();
app.use(express.json());
app.use('/auth', authRoute);
mongoose.connect(process.env.MONGO).then(() => {
console.log('Database Connected')
});
const PORT = process.env.PORT || 5000;
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"));
});
}
app.listen(PORT, () => {
console.log(`Server Online at ${PORT}`);
});
module.exports = mongoose.model('Users', userSchema);
I think it doesn't work because transporter.sendMail() is asynchronous function you have to use async await to execute that function.
Try this
token.save(async () => {
if(err) {
return res.status(500).send({msg: err.message});
}
let transporter = nodemailer.createTransport({service: 'gmail', auth: {user: 'myEmail', pass: "Password"}});
let mailOptions = {from: "authmail14#gmail.com", to: user.email, subject: "Account Verification Link"}
await transporter.sendMail(mailOptions, function(err) {
if(err) {
return res.status(500).send({msg: "Technical Issue"})
}
return res.status(200).send('Email Sent')
})
});
Dharmik Patel's answer problematic
Either you use async/await to run synchronous code, or you use a callbak or promise for asynchronous code.
But not both at the same time.
Here is an example with callback :
mailer.transport.sendMail( mail_config, function( error ) {
if ( error ) {
console.info( 'Mail not sent : ', error );
return;
}
console.info( 'Mail sent ! ');
message.transport.close();
});
Just add console for printing error of mailler callback to see what is the problem.
In general, use promises or calbacks instead to keep the asynchronous advantage of node.js.
Synchronous operation must be reserved for processing that cannot be done asynchronously.
I am new to mongoose and express. I try to create a simple login backend, however when send a post request with
{
"userEmail": "abc#xyz", "password": "pswrd"
}
I get "email is not defined" error whose type is "VALIDATION". My User Schema is as follows:
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const UserSchema = new mongoose.Schema({
email: {
type: String,
required: [true, "Email is required"],
trim: true,
unique: true,
},
password: {
type: String,
trim: true,
required: [true, "Password is required"],
},
username: {
type: String,
required: [true, "Username is required"],
trim: true,
unique: true,
},
});
UserSchema.pre("save", async function (next) {
const user = await User.findOne({ email: this.email });
if (user) {
next(new Error(`${this.email} already taken`));
return;
}
const user1 = await User.findOne({ username: this.username });
if (user1) {
next(new Error(`${this.username} already taken`));
return;
}
const salt = await bcrypt.genSalt(8);
this.password = await bcrypt.hash(this.password, salt);
next();
});
// userSchema.statics is accessible by model
UserSchema.statics.findByCredentials = async (email, password) => {
const user = await User.findOne({ email });
if (!user) {
throw Error("User does not exist.");
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
throw Error("Unable to login");
}
return user;
};
const User = mongoose.model("User", UserSchema);
module.exports = User;
I use findByCredentials to check if the User is in my mongoDB database or not. Finally, my login.js is as follows:
const express = require("express");
const mongoose = require("mongoose");
const User = require("../db/models/User");
const loginRouter = express.Router();
loginRouter.get("/api/login2", (req, res) => res.send("In Login"));
loginRouter.post("/api/login", async (req, res) => {
const { userEmail, password} = req.body;
if (!validateReqBody(userEmail, password)) {
return res
.status(401)
.send({ status: false, type: "INVALID", error: "invalid request body" });
}
try {
const newUser = new User({
email: userEmail,
password: password,
});
await newUser.findByCredentials(email, password);
} catch (error) {
const validationErr = getErrors(error);
console.log(validationErr);
return res
.status(401)
.send({ status: false, type: "VALIDATION", error: validationErr });
}
res.send({ status: true });
});
//user.find --> mongoose documentation
// Validates request body
const validateReqBody = (...req) => {
for (r of req) {
if (!r || r.trim().length == 0) {
return false;
}
}
return true;
};
// Checks errors returning from DB
const getErrors = (error) => {
if (error instanceof mongoose.Error.ValidationError) {
let validationErr = "";
for (field in error.errors) {
validationErr += `${field} `;
}
return validationErr.substring(0, validationErr.length - 1);
}
return error.message;
};
module.exports = { loginRouter };
Thank you.
You need to use body-parser middleware in backend
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
//bodypraser middleware
app.use(bodyParser.json());
You can read more about bodyparser here
Happened to me once, it was really annoying. I don't know If it would help you, but try sending the post request with headers: { 'Content-Type': 'application/json' }, using fetch.
Definition of findByCredentials() is in User model. I was trying to reach that function by the object instance newUser that i created in login.js. However, i should have called the function as User.findByCredentials(email, password).
so hello everyone i'm devolpping my authentication backend i set up my routers my models middlewares and everything then i tried to use postman to see if the registation work or not and each time i click on send request nothing happen i don't know what should i do exactly so please can anyone help with this
database/db.js // connection to database
const mongoose = require('mongoose')
require('dotenv').config();
const base = process.env.MONGO_DATA;
try {
mongoose.connect( base,
{useNewUrlParser: true, useCreateIndex: true}, () =>
console.log("database connected"));
}catch (error) {
console.log("could not connect");
}
models/user.model.js
const mongoose = require('mongoose')
const validator = require('validator')
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const userSchema = mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
unique: true,
lowercase: true,
validate: value => {
if (!validator.isEmail(value)) {
throw new Error({error: 'Invalid Email address'})
}
}
},
password: {
type: String,
required: true,
minLength: 7
},
tokens: [{
token: {
type: String,
required: true
}
}]
})
userSchema.pre('save', async function (next) {
// Hash the password before saving the user model
const user = this
if (user.isModified('password')) {
user.password = await bcrypt.hash(user.password, 8)
}
next()
})
userSchema.methods.generateAuthToken = async function() {
// Generate an auth token for the user
const user = this
const token = jwt.sign({_id: user._id}, process.env.JWT_KEY)
user.tokens = user.tokens.concat({token})
await user.save()
return token
}
userSchema.statics.findByCredentials = async (email, password) => {
// Search for a user by email and password.
const user = await User.findOne({ email} )
if (!user) {
throw new Error({ error: 'Invalid login credentials' })
}
const isPasswordMatch = await bcrypt.compare(password, user.password)
if (!isPasswordMatch) {
throw new Error({ error: 'Invalid login credentials' })
}
return user
}
const User = mongoose.model('User', userSchema)
module.exports = User
controllers/user.js
const express = require('express')
const User = require('../models/user.model')
const router = express.Router()
router.post('/users', async (req, res) => {
// Create a new user
try {
const user = new User(req.body)
await user.save()
const token = await user.generateAuthToken()
res.status(201).send({ user, token })
} catch (error) {
res.status(400).send(error)
}
})
router.post('/users/login', async(req, res) => {
//Login a registered user
try {
const { email, password } = req.body
const user = await User.findByCredentials(email, password)
if (!user) {
return res.status(401).send({error: 'Login failed! Check authentication credentials'})
}
const token = await user.generateAuthToken()
res.send({ user, token })
} catch (error) {
res.status(400).send(error)
}
})
module.exports = router
index.js
require('dotenv').config()
const express = require('express')
const userRouter = require('./src/routers/user')
const port = process.env.PORT
require('./src/database/db')
const app = express()
app.use(express.json())
app.use(userRouter)
app.listen(port, () => {
console.log(`Server running on port ${port}`)
})
so each time i try to see if i'm signed up or not postman didn't give any response he keep saying <> and no result can someone help me please ?
Have you created " data " and " db " folder in your ' C ' drive?
Here are the steps:
Create a folder on your machine with name mongodb
Create a folder with name data in the mongodb folder
Create one more folder with name db in the data folder
For more, refer here