ValidationError in mongoose- because of "CastError" - javascript

Am trying to create users and their posts. Each user has an array of posts, a user can create a post and the user is being verified by a jwt token when he/she logins. This is what i get after i try to make a post. I would really appreciate if you could help me out on this one
ValidationError: Post validation failed: content: Cast to Boolean failed for value "My first post" (type string) at path "content" because of "CastError", user: Path user is required
userSchema:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
username:{
type:String,
required:true
},
email:{
type:String,
required:true
},
password:{
type:String,
required:true
},
posts:[{
type:mongoose.Schema.Types.ObjectId, ref:"Post"
}]
})
module.exports = mongoose.model('User', userSchema)
post schema
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema(
{
user:{type:mongoose.Schema.Types.ObjectId,
required:true,
ref:'User'
},
title:{
type:String,
required:true
},
content:{
type:Boolean,
required:true
},
createdAt:{
type:Date,
default: new Date()
},
likes:{
type:Number,
default:0
}
})
module.exports = mongoose.model('Post', postSchema)
postcontroller
const Post = require('../models/Posts')
const User = require('../models/User')
const expressAsyncHandler = require('express-async-handler')
const getAllPosts = async (req,res)=>{
const posts = await Post.find().lean()
if(!posts?.length){
res.status(400).json({message:"No posts Found"})
}
const postsWithUsers = await Promise.all(posts.map(async(post) =>{
const user = await User.findById(post.user).lean().exec()
return {...post, username: user.username}
}))
res.json(postsWithUsers)
}
const createPost = expressAsyncHandler(async(req, res) =>{
const { title, content} = req.body
// console.log(id)
if( !title||!content){
return res.status(400).json({message:"All Fields"})
}
const new_post = await Post.create({
// user,
title,
content
})
if(new_post){
return res.status(201).json({
//_id:new_post._id,
title:new_post.title,
content:new_post.content,
likes:new_post.likes,
created_on:new_post.createdAt,
//user:new_post.user
})
}else{
return res.status(400).json({message:"Invalid Data received"})
}
})
module.exports = {
createPost,
getAllPosts
}
authcontroller
const User = require('../models/User');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const asyncHandler = require('express-async-handler')
const login = asyncHandler(async(req,res) =>{
const {email, password} = req.body
if(!email||!password){
return res.status(400).json({message:"All Fields are Required"})
}
const user = await User.findOne({email}).exec()
if(!user){
return res.status(401).json({message:"user does not Exist"})
}
const match = await bcrypt.compare(password, user.password)
if(!match) return res.status(401).json({message:"Unauthorized"})
const accessToken = jwt.sign(
{
"UserInfo": {
"username": user.username,
"posts":user.posts
}
},
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: '7d' }
)
const refreshToken = jwt.sign(
{
"UserInfo":{
"username":user.username,
"posts":user.posts
}
},
// console.log(user.username),
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: '7d' },
//console.log(user.posts)
)
res.cookie('jwt', refreshToken, {
httpOnly: true, //accessible only by web server
secure: true, //https
sameSite: 'None', //cross-site cookie
maxAge: 7 * 24 * 60 * 60 * 1000 //cookie expiry: set to match rT
})
res.json({ accessToken })
})
module.exports = login
authmiddleware
const jwt = require('jsonwebtoken')
const verifyJWT = (req,res,next) =>{
const authHeader = req.headers.authorization || req.headers.Authorization
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ message: 'You Need to Login First' })
}
const token = authHeader.split(' ')[1]
jwt.verify(
token,
process.env.ACCESS_TOKEN_SECRET,
(err, decoded) =>{
if(err) return res.status(403).json({message:"Thats Forbidden"})
req.user = decoded.UserInfo.username
next()
}
)
}
module.exports = verifyJWT

Related

GraphQL HTTP: "Cannot return null for non-nullable field Mutation.register."

I am trying to mutate in GraphQL to create a new user but I get the error of
Cannot return null for non-nullable field Mutation.register.
Screenshot of operation, variable and response here.
graphql/schema/schema.js
const{ buildSchema } = require('graphql');
const schema = buildSchema(`
type User {
_id: ID!
email: String!
username: String!
token: String!
createdAt: String!
}
input RegisterInput{
username: String!
password: String!
confirmPassword: String!
email: String!
}
type Query {
user(id: ID!): User
}
type Mutation {
register(registerInput: RegisterInput): User!
}
schema {
query: Query
mutation: Mutation
}
`)
module.exports = schema;
graphql/resolvers/user.js
const User = require('../../models/user.js');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const SECRET_KEY = 'oPXA96op!u%,`:}eT^.!|hvXohA~fa';
module.exports = {
Mutation: {
async register(
_,
{
registerInput: { username, email, password, confirmPassword}
},
context,
info
) {
password = await bcrypt.hash(password, 12);
const newUser = new User({
email,
username,
password,
createdAt: new Date().toISOString
});
const res = await newUser.save();
const token = jwt.sign({
id: res.id,
email: res.email,
username: res.username
}, SECRET_KEY, { expiresIn: '1h'});
return{
...res._doc,
id: res._id,
token
};
}
}
};
graphql/resolvers/index.js
const postResolver = require('./post');
const userResolver = require('./user');
const resolvers = {
Mutation: {
...userResolver.Mutation
},
...postResolver
}
module.exports = resolvers;
server.js
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');
const mongoose = require('mongoose');
const cors = require('cors');
const { graphqlHTTP } = require('express-graphql');
const MONGODB = '';
const schema = require('./graphql/schema');
const resolvers = require('./graphql/resolvers');
const PORT = 4000;
const server = new ApolloServer({ schema, resolvers });
mongoose.connect(MONGODB);
mongoose.connection.once('open', function() {
console.log('Connected to the Database.');
});
mongoose.connection.on('error', function(error) {
console.log('Mongoose Connection Error : ' + error);
});
const app = express();
app.use(cors());
let apolloServer = null;
async function startServer() {
apolloServer = new ApolloServer({
schema,
resolvers,
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
}
startServer();
app.use("/graphql", graphqlHTTP({
schema: schema,
rootValue: resolvers,
graphiql: true
}));
app.listen(PORT, function() {
console.log(`Server listening on port ${PORT}.`);
});
I have checked many previous posts about this mutation error but none have seen to be resolved, and also have done many modifications to the schema/resolver but has not worked. I have also posted on the GraphQL Discord for help, but have had no luck. I tried changing the server.js but it affected my queries from running so I reverted.
/graphql/resolvers/post.js
const Post = require('../../models/post.js');
const { GraphQLDateTime } = require ('graphql-iso-date');
const customScalarResolver = {
Date: GraphQLDateTime
};
function posts() {
return Post.find({});
}
function post(args) {
return Post.findById(args.id)
}
function createPost(args) {
let post = new Post(args.postInput);
return post.save();
}
function deletePost(args) {
return Post.findByIdAndRemove(args.id);
}
function updatePost(args) {
return Post.findByIdAndUpdate(args.id, args.postInput, { new: true });
}
module.exports = { posts, post, createPost, deletePost, updatePost, customScalarResolver}

Monggose array schema type not passing more than one items

I am trying to pass an array of schemas that will populate multiple social media documents in the qrCode document but when I send the post request using Postman it only sends 1 of them.
This is the QrCode Modle where the shcema is being defined
const Joi = require("joi");
const mongoose = require("mongoose");
const { themeSchema } = require("./Theme");
const { userSchema } = require("./User");
const { socialSchema } = require("./Social");
const QrCode = mongoose.model(
"QrCode",
new mongoose.Schema({
user: {
type: userSchema,
required: true,
},
name: {
type: String,
maxLength: 255,
required: true,
trim: true,
},
theme: {
type: themeSchema,
required: true,
},
// Social Media Links
social: [
{
type: socialSchema,
required: true,
},
],
})
);
function ValidateQrCode(qrCode) {
const schema = {
userId: Joi.objectId(),
name: Joi.string().max(255).required(),
themeId: Joi.objectId().required(),
socialId: Joi.array().required().items(Joi.string()),
};
return Joi.validate(qrCode, schema);
}
module.exports.QrCode = QrCode;
module.exports.validate = ValidateQrCode;
This is the post route to create a new qrCode
const { QrCode, validate } = require("../models/QrCode");
const { Theme } = require("../models/Theme");
const { User } = require("../models/User");
const { Social } = require("../models/Social");
const auth = require("../middleware/auth");
const express = require("express");
const router = express.Router();
router.get("/", async (req, res) => {
const qrCodes = await QrCode.find().sort("-name");
res.send(qrCodes);
});
router.post("/", auth, async (req, res) => {
const { error } = validate(req.body);
if (error) res.status(400).send(error.details[0].message);
const theme = await Theme.findById(req.body.themeId);
if (!theme) return res.status(400).send("Invalid theme.");
const social = await Social.findById(req.body.socialId);
if (!social) return res.status(400).send("Invalid social.");
const user = await User.findById(req.user._id);
if (!user) return res.status(400).send("Invalid theme.");
const qrCode = new QrCode({
user: user,
name: req.body.name,
theme: theme,
social: social,
});
await qrCode.save();
res.send(qrCode);
});
module.exports = router;
This is the postman post request that I send
{
"name": "Test399",
"themeId": "60f607ab97943dfaa05811bc",
//the ID's for all the socials
"socialId": ["60f657f97f90bb0cd10cfef1", "60f77d179b05d91894ef32ab"]
}
Your route has
const social = await Social.findById(req.body.socialId);
here you are trying to pass array and Mongoose findById document says to send the _id for query, that is the reason mongoose gives only one value.
Iterate over the array and get values before sending the response.

Passport.js throws error, MissingSchemaError(name)

Trying to code the backend, and this throws an error in the console. What could be the problem? I imported user.js as a requirement, but still does not work.
Error: mongoose.Error.MissingSchemaError(name); Schema hasn't been registered for model "User". Use mongoose.model(name, schema)
Passport.js
const passport = require('passport');
const user = require('../schema/user');
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const User = mongoose.model('User');
passport.use(new LocalStrategy({
usernameField: 'email'
},
(username, password, done) => {
User.findOne({ email: username }, (err, user) => {
if (err) { return done(err); }
if (!user) {
return done(null, false, {
message: 'Incorrect username.'
});
}
if (!user.validPassword(password)) {
return done(null, false, {
message: 'Incorrect password.'
});
}
return done(null, user);
});
}
));
User.js
const mongoose = require("mongoose");
const crypto = require('crypto');
const jwt = require('jsonwebtoken');
const userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
name: {
type: String,
required: true
},
hash: String,
salt: String
});
userSchema.methods.setPassword = function (password) {
this.salt = crypto.randomBytes(16).toString('hex');
this.hash = crypto
.pbkdf2Sync(password, this.salt, 1000, 64, 'sha512')
.toString('hex');
};
userSchema.methods.validPassword = function (password) {
const hash = crypto
.pbkdf2Sync(password, this.salt, 1000, 64, 'sha512')
.toString('hex');
return this.hash === hash;
};
userSchema.methods.generateJwt = function () {
const expiry = new Date();
expiry.setDate(expiry.getDate() + 7);
return jwt.sign({
_id: this._id,
email: this.email,
name: this.name,
exp: parseInt(expiry.getTime() / 1000, 10),
}, process.env.JWT_SECRET );
};
module.exports = mongoose.model('User', userSchema);
in passport.js file, you don't need to require require('mongoose') and mongoose.model('User'), so delete them and change user to User like this:
const passport = require('passport');
const User = require('../schema/user');// change user to User
const LocalStrategy = require('passport-local').Strategy;

How to save a given model in a specific collection in the database mongodb?

I have three models: user, teacher, student. The users, teachers, students collections appear in the database. But everything is saved in the users collection. How to set up in the code below that student is saved in the students collection, not in users.
model
const mongoose = require('mongoose');
extend = require('mongoose-extend-schema');
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: {
type: String,
trim: true,
required: true,
maxLength: 32
},
surname: {
type: String,
trim: true,
required: true,
maxLength: 32
},
email: {
type: String,
unique: true,
trim: true,
required: true,
lowercase: true
},
initials: String
});
const studentSchema = extend(userSchema, {
teachers: []
});
const teacherSchema = extend(userSchema, {
isActiveTutor: {
type: Boolean,
default: false
}
})
const User = mongoose.model('User', userSchema);
const Student = mongoose.model('Student', studentSchema);
const Teacher = mongoose.model('Teacher', teacherSchema);
module.exports = {
User,
Student,
Teacher
}
controllers
const User = require('../models/user');
const Student = require('../models/user');
const Teacher = require('../models/user');
const jwt = require('jsonwebtoken');
const nodemailer = require('nodemailer');
const expressJwt = require('express-jwt');
module.exports.signup = (req, res) => {
const {name, surname, email, password, initials, role} = req.body;
Student.User.findOne({email}).exec((err, student) => {
if (student) {
return res.status(400).json({
error: "Email is taken"
})
}
}
}
module.exports.accountActivationStudent = (req, res) => {
const {token} = req.body;
if(token) {
jwt.verify(token, process.env.JWT_ACCOUNT_ACTIVATION, function(err, decoded) {
if(err) {
console.log('JWT VERIFY IN ACCOUNT ACTIVATION ERROR', err);
return res.status(401).json({
error: 'Expired link. Signup again'
})
}
const {name, surname, email, password} = jwt.decode(token);
const student = new Student.User ({name, surname, email, password});
student.save((err, student) => {
if(err) {
console.log('SAVE Student IN ACCOUNT ACTIVATION ERROR', err);
return res.status(401).json({
error: 'Error saving student in database. Try signup again'
});
}
return res.json({
message: 'Signup success. Please signin'
});
});
});
} else {
return res.json({
message: 'Something went wrong. Try again'
})
}
};
new Student is your schema
try to like this
router.post('/', async (req, res) => {
const _studentSave = await new Student({ name, surname, email, password, initials, role });
const saveProcess = await _studentSave.save();
try{
res.json(saveProcess)
}catch(error){
throw error
}
})

My app is crashing during JWT Authentication

I am new to MERN stack development and trying the JWT authentication. During this I am facing that my server is not working they crashed every time.
Yesterday It was working but today It's not working. Now they are showing this error.
This is error showing on console
MissingSchemaError: Schema hasn't been registered for model "users".
Here is my Schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
avatar: {
type: String
},
date: {
type: Date,
default: Date.now
}
});
const User = mongoose.model('users', UserSchema);
module.exports = User;
This code is in the routes folder - user.js file
// user.js
const express = require('express');
const router = express.Router();
const gravatar = require('gravatar');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const passport = require ('passport');
const validateRegisterInput = require('../validation/register');
const validateLoginInput = require('../validation/login');
const User = require('../models/User');
//Register Post Router
router.post('/register', function(req, res){
const {errors, isValid} = validateRegisterInput(req.body);
if(!isValid){
return res.status(400).json(errors);
}
User.findOne({
email: req.body.email
}).then(user => {
if(user){
return res.status(400).json({
email: 'Email already exists'
});
}
else {
const avatar = gravatar.url(req.body.email, {
s: '200',
r: 'pg',
d: 'mm'
});
const newUser = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password,
avatar
});
bcrypt.genSalt(10, (err, salt) => {
if(err)
console.error('There was an error', err);
else{
bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err)
console.error('There was an error', err);
else{
newUser.password = hash;
newUser
.save()
.then(user => {
res.json(user)
});
}
});
}
});
}
});
});
//Login Post Router
router.post('/login', (req, ress) => {
const {errors, isValid} = validateLoginInput(req.body);
if(isValid){
return res.status(400).json(errors);
}
const email = req.body.email;
const password = req.body.password;
User.findOne({email})
.then(user => {
if(!user) {
errors.email = 'User not found'
return res.status(404).json(errors);
}
bcrypt.compare(password, user.password)
.then(isMatch => {
if(isMatch){
const payload = {
id: user.id,
name: user.name,
avatar: user.avatar
}
jwt.sign(payload, 'secret', {
expiresIn: 3600
}, (err, token) => {
if(err)
console.error('There is some error in token', err);
else{
res.json({
success: true,
token: `Bearer ${token}`
});
}
});
}
else{
errors.password = 'Incorrect Password';
return
res.status(400).json(errors);
}
});
});
});
router.get('/me', passport.authenticate('jwt', {session: false}), (req, res) => {
return res.json({
id: req.user.id,
name: req.user.name,
email: req.user.email
});
});
module.exports = router;

Categories

Resources