I'm receiving an invalid inputs error on my signup POST request on Postman. I've checked my User Model attributes but can't seem to find exactly which input(s) is/are being called invalid. Here is my model, controller, route. and app.js. Kindly take a look.
App
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const usersRoutes = require('./routes/users-routes');
const postsRoutes = require('./routes/posts-routes');
const HttpError = require('./models/http-error');
const app = express();
app.use(bodyParser.json());
app.use('/api/users', usersRoutes);
app.use('/api/posts', postsRoutes);
app.use((req, res, next) => {
const error = new HttpError('Could not find this route.', 404);
throw error;
})
app.use((error, req, res, next) => {
if (res.headerSent) {
return next(error);
}
res.status(error.code || 500)
res.json({ message: error.message || 'An unknown error occurred!' });
});
const connectUrl = 'hidden';
const connectConfig = {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
}
mongoose
.connect(connectUrl, connectConfig)
.then(() => {
app.listen(5000);
})
.catch(err => {
console.log(err);
});
User model
const userSchema = new Schema({
username: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
avatarUrl: { type: String, required: true },
posts: [{ type: mongoose.Types.ObjectId, required: true, ref: 'Post' }]
});
Users controller
const signup = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return next(
new HttpError('Invalid inputs passed, please check your data.', 422)
);
}
const { username, email, password } = req.body;
let existingUser
try {
existingUser = await User.findOne({ email: email })
} catch (err) {
const error = new HttpError('Signing up failed, please try again later.', 500);
return next(error);
}
if (existingUser) {
const error = new HttpError('User exists already, please login instead.', 422);
return next(error);
}
const createdUser = new User({
username,
email,
password,
avatarUrl: 'https://images.pexels.com/photos/406014/pexels-photo-406014.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260',
posts: []
});
try {
await createdUser.save();
} catch (err) {
const error = new HttpError('Signup failed, please try again.', 500);
return next(error);
}
res.status(201).json({ user: createdUser.toObject({ getters: true })});
}
User routes
router.post(
'/signup',
[
check('username').not().isEmpty(),
check('email').normalizeEmail().isEmail(),
check('password').isLength({ min: 6 })
],
usersController.signup
);
Postman
Make sure you using body parser in your middleware:
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
Thank you #SuleymanSah for the answer (sorry, I don't know how to mark your comment above as the answer)
The issue was that the Headers box for Content-Type: application/json on Postman was unchecked. Checking the box solved the invalid inputs issue.
Related
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 am creating a MERN stack based website, and was able to write GET and POST requests for two out of the three models I have created so far: users and profile. The latest one, tests, is giving an error of Cannot POST /api/tests. Here's the code:
server.js
const connectDB = require('./config/db');
const app = express();
//Connecting DB
connectDB()
app.use(express.json({extended: false}));
app.get('/',(req,res)=>res.send('API Running'));
app.use('/api/users',require('./routes/api/users'));
app.use('/api/auth',require('./routes/api/auth'));
app.use('/api/profile',require('./routes/api/profile'));
app.use('/api/tests', require('./routes/api/tests'));
const PORT = process.env.Port || 5000;
app.listen(PORT, ()=> console.log(`Server started on port on ${PORT}`));
Test.js
const TestSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
domain: {
type: String,
required: true
},
activeStatus: {
type: Boolean,
required: true
},
questions: [
{
question: {
type: String,
required: true
},
option1: {
type: String,
required: true
},
option2: {
type: String,
required: true
},
option3: {
type: String,
required: true
},
option4: {
type: String,
required: true
},
answer: {
type: Number,
required: false
}
}
]
});
module.exports = Test = mongoose.model('test', TestSchema);
tests.js
const router = express.Router();
const { check, validateResult } = require('express-validator/check');
const auth = require('../../middleware/Auth');
const Test = require('../../models/Test');
const User = require('../../models/User');
// #route POST api/tests
// #desc Create or Update a test
// #access Private
router.post('/', [
check('name', 'Name is required').not().isEmpty(),
check('domain', 'Domain is required').not().isEmpty(),
check('status', 'Status is required').not().isEmpty()
],
async (req, res) => {
console.log("entered");
const errors = validationResult(req);
if(!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
name,
domain,
status
} = req.body;
//build test object
const testFields = {};
if(name) testFields.name = name;
if(domain) {console.log(123); testFields.domain = domain;}
if(status) testFields.status = status;
testFields.questions = {};
try {
//see if test exists
// let test = await Test.findOne({name});
// if(test){
// return res.status(400).json({ errors: [{msg: "Test already exists"}] });
// }
//create
test = new Test(testFields);
await test.save();
res.json(test);
console.log(testFields);
res.send('Test Created')
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
// #route GET api/tests
// #desc Get particular test
// #access Private
router.get('/', auth, async (req, res) => {
try {
const test = await Profile.findById(req.test.id);
console.log(test);
if(!test)
return res.status(400).json({ msg: 'Test not found' });
res.json(test);
} catch (err) {
console.error(err.message);
res.status(500).send('Server Error');
}
});
module.exports = router;
Things I've already tried:
Checked and rechecked the URL entered in Postman (http://localhost:5000/api/tests)
Set the URL type in Postman to POST
Made sure the URL was properly registered, and compared with working URLs and files
Even after this, nothing has worked so far. I am fairly new to this, so that might be the cause of my oversight, please do let me know if you can spot where it's going wrong.
I have a middleware that uses express-validator to validate request,
const { validationResult } = require("express-validator");
module.exports = {
validate: (req, res, next) => {
const raw_errors = validationResult(req);
if (raw_errors.isEmpty()) {
return next()
}
const errors = raw_errors.errors.map((err) => ({ message: err.msg }));
return res.status(422).json({ status: "error", errors });
},
}
I use it on the route like so:
const { validate } = require('../middlewares/validation')
routes.post('/', validate, (req, res) => {
postService.add(req.body.name, req.body.description).then(post => {
res.status(201).json({ message: 'post added', data: post })
}).catch(error => {
handleError(error, res)
})
})
But when i try to make an API call with an empty request body, it does not return any errors.
Here is my model
const mongoose = require('mongoose');
const PostSchema = mongoose.Schema( {
name: {
type: String,
required: [true, 'Please provide a name'],
},
description: {
type: String,
required: [true, 'Please provide a description'],
}
},
{timestamps: true}
);
module.exports = mongoose.model('Post', PostSchema);
Here is my postService
module.exports = {
//adds a post
add : async (name, description) => {
try{
const tab = { name, description }
return postModel.create(tab)
}
catch(err){
throw new ErrorHandler(500, "Unable to add post at this time. Please try again later.")
}
},
}
When I log raw_errors from the middleware, I get - Result { formatter: [Function: formatter], errors: [] }
Please what might be wrong?
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).
It does not return anything back (hang state) and i see in console
{ _id: 5f05d1527de7984a2c998385, name: 'alexa', age: 12 }. I tried both method promise and callback but still same. Can you guess what could be the issue?
const express = require('express');
const app = express();
const mongoose = require('mongoose');
app.use(express.json());
const TestModel = mongoose.model(
'test',
new mongoose.Schema({
name: {
type: String,
required: true,
},
age: {
type: Number,
required: true,
},
}),
);
app.post('/test', async (req, res, next) => {
const testUser = req.body;
const Test = new TestModel(testUser);
console.log(Test);
/* Test.save(function (err, doc) {
if (err) {
return res.json({ message: 'something went wrong' });
}
res.json(testUser);
}); */
await Test.save();
res.json(testUser);
});
app.listen(4000, () => {
console.log('playground is up');
});