req.body
is empty in Node.js Express API route when sending JSON request using Postman.
This is the error:
<pre>Error: Username or email is required<br> at file:///C:/Users/hrshl/OneDrive/Desktop/Harshal/Web%20dev/vdeohub-backend/src/controllers/user.controller.js:117:15</pre>
This part is causing the error:
if (!username && !email) {
throw new ApiError(400, 'Username or email is required');
}
This is the loginUser
function which was giving the error:
const loginUser = asyncHandler(async (req, res) => {
// Take the data from the frontend - username/email and password
// Validate the user details - if all fields are present or not
// Check if the username/email exists in database
// If yes, check if the password is correct or not using isPasswordCorrect method
// create an access token and a refresh token+
const generateAccessAndRefreshTokens = async (userId) => {
try {
user = User.findById(userId);
const accessToken = user.generateAccessToken();
const refreshToken = user.generateRefreshToken();
user.refreshToken = refreshToken;
user.save({ validateBeforeSave: false });
return { accessToken, refreshToken };
} catch (error) {
return new ApiError(
500,
'Something went wrong while generating access and refresh tokens'
);
}
};
const { username, email, password } = req.body;
// console.log(req.body);
if (!username && !email) {
throw new ApiError(400, 'Username or email is required'); //error from here
}
const user = await User.findOne({
$or: [{ username }, { email }],
});
if (!user) {
return new ApiError(404, 'User does not exists');
}
if (!password) {
return new ApiError(400, 'Password is required');
}
const isPasswordValid = user.isPasswordCorrect(password);
if (!isPasswordValid) {
throw new ApiError(401, 'Invalid user credentials');
}
const { accessToken, refreshToken } = await generateAccessAndRefreshTokens(
user._id
);
const loggedInUser = User.findById(user._id).select(
'-password -refreshToken'
);
options = {
httpOnly: true,
secure: true,
};
return res
.status(200)
.cookie('refreshToken', refreshToken, options)
.cookie('accessToken', accessToken, options)
.json(
new ApiResponse(
200,
{ user: loggedInUser, accessToken, refreshToken },
'User logged in successfully'
)
);
});
This is the asyncHandler
utility:
const asyncHandler = (requestHandler) => {
return (req, res, next) => {
Promise.resolve(requestHandler(req, res, next)).catch((err) =>
next(err)
);
};
};
export { asyncHandler };
This is the user model:
import mongoose from 'mongoose';
import bcrypt from 'bcrypt';
import JWT from 'jsonwebtoken';
const userSchema = new mongoose.Schema(
{
username: {
type: String,
required: [true, 'Username is required...'],
unique: true,
lowercase: true,
trim: true,
index: true,
},
email: {
type: String,
required: [true, 'Email is required...'],
unique: true,
lowercase: true,
trim: true,
},
fullName: {
type: String,
required: [true, 'Full name is required...'],
trim: true,
index: true,
},
avatar: {
type: String, //Cloudinary URL
required: [true, 'Avatar is required...'],
},
coverImage: {
type: String, //Cloudinary URL
},
watchHistory: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Video',
},
],
password: {
type: String,
required: [true, 'Password is required...'],
minlength: [6, 'Password must be at least 6 characters...'],
},
},
{
timestamps: true,
}
);
userSchema.pre('save', async function (next) {
if (this.isModified('password')) {
this.password = await bcrypt.hash(this.password, 10);
}
next();
});
userSchema.methods.isPasswordCorrect = async function (password) {
return await bcrypt.compare(password, this.password);
};
userSchema.methods.generateAccessToken = function () {
return JWT.sign(
{
_id: this._id,
},
process.env.ACCESS_TOKEN_SECRET,
{
expiresIn: process.env.ACCESS_TOKEN_EXPIRY,
}
);
};
userSchema.methods.generateRefreshToken = function () {
return JWT.sign(
{
_id: this._id,
},
process.env.REFRESH_TOKEN_SECRET,
{
expiresIn: process.env.REFRESH_TOKEN_EXPIRY,
}
);
};
export const User = mongoose.model('User', userSchema);
If you need to look at the entire codebase, head to my GitHub repo.
There is also a registerUser
function, and it also takes in arguments from req.body
, but that one works perfectly fine:
const registerUser = asyncHandler(async (req, res) => {
// get user details from frontend
// validate the user details - if all the fields are present or not
// check if user already exixts in database - username, email
// if user exists send error response to frontend
// check if the user has uploaded a profile picture/avatar
// if yes, upload the image to cloudinary
// check for the image uploaded to cloudinary successfully or not
// if yes, save the user details to a new user object
// create a new user in the database
// remove the password and the refreshToken from the response
// check for user creation success or failure
// if success, send the response to the frontend
const { fullName, email, username, password } = req.body;
console.log(req.body);
if (
[fullName, email, username, password].some(
(field) => field?.trim() === ''
)
) {
throw new ApiError(400, 'All fields are required');
}
const existedUser = await User.findOne({
$or: [{ email }, { username }],
});
if (existedUser) {
throw new ApiError(409, 'User already exists');
}
console.log(req.files);
const avatarLocalPath = req.files?.avatar[0]?.path;
const coverImageLocalPath = req.files?.coverImage?.[0]?.path;
if (!avatarLocalPath) {
throw new ApiError(
400,
'Avatar is required. Avatar not found in request body'
);
}
const avatar = await uploadToCloudinary(avatarLocalPath);
let coverImage;
if (!(coverImageLocalPath === undefined)) {
coverImage = await uploadToCloudinary(coverImageLocalPath);
}
if (!avatar) {
throw new ApiError(
400,
'Avatar is required. Failed to upload avatar to cloudinary'
);
}
const user = await User.create({
fullName: fullName,
email: email,
username: username.toLowerCase(),
password: password,
avatar: avatar.url,
coverImage: coverImage?.url || '',
});
const createdUser = await User.findById(user._id).select(
'-password -refreshToken'
);
if (!createdUser) {
throw new ApiError(500, 'Failed to create user. Something went wrong.');
}
return res
.status(201)
.json(new ApiResponse(200, createdUser, 'User created successfully'));
});
I tried console logging the entire request, and it was fine, just the request.body
was empty. I also tried adding bodyparser, but it didn’t do anything. I also tried changing the check to:
if (!(username || email)) {
throw new ApiError(400, 'Username or email is required');
}
but still no luck.