3
\$\begingroup\$

I'm looking for a review of my backend code on how to keep it more DRY. I see a lot of repetition in validation part of email and password, also I need some advice on if I have used the try-catch and async/await correctly. And most importantly, the thing that I have to clear is the sending of response back. Sometimes, I get this error of Can't set headers after they are sent to the client. I know this arises when I'm trying to send two responses back, but I need a review on how do I structure my response sending so that I don't get this error.

Also, as you can see below code that I've used mostly:

 catch (error) {
      return next(error)

but when I tried to do the same in getUserPosts, I got the same error that I've described above. So, I had to change it to:

 catch (error) {
      console.log(error)

I don't know if this a good way to handle errors.


Here's my code with models and controller functions.

models

User.js

const mongoose = require("mongoose")
const bcrypt = require("bcrypt")
const Schema = mongoose.Schema

const userSchema = new Schema({
    username: { type: String, required: true },
    email: { type: String, reuired: true },
    password: { type: String, required: true },
    posts:[{ type: Schema.Types.ObjectId, ref: "Post" }]
}, { timestamps: true })


userSchema.methods.confirmPassword = function (password) {
    return bcrypt.compareSync(password, this.password)
}

const User = mongoose.model("User", userSchema)

module.exports = User

Post.js

const mongoose = require("mongoose");
const Schema = mongoose.Schema;
var URLSlug = require("mongoose-slug-generator");

mongoose.plugin(URLSlug);

const postSchema = new Schema({
  title: { type: String, required: true },
  description: { type: String, required: true },
  user: { type: Schema.Types.ObjectId, ref: "User" },
  slug: { type: String, slug: "title" },
}, { timestamps: true }
)

postSchema.pre("save", function (next) {
  this.slug = this.title.split(" ").join("-");
  next();
});

const Post = mongoose.model("Post", postSchema);

module.exports = Post;

usersController.js

const User = require("../models/User")
const auth = require("../utils/auth")
const validator = require("validator")
const bcrypt = require("bcrypt")

module.exports = {
  registerUser: async (req, res, next) => {
    try {
      var { username, email, password } = req.body
      if (password) {
        const salt = bcrypt.genSaltSync(10)
        password = bcrypt.hashSync(password, salt)
      }
      if (!username || !email || !password) {
        return res
          .status(400)
          .json({ message: "Username, email and password are must" })
      }
      if (!validator.isEmail(email)) {
        return res.status(400).json({ message: "Invaid email" })
      }
      if (password.length < 6) {
        return res
          .status(400)
          .json({ message: "Password should be of at least 6 characters" })
      }
      const user = await User.create({ username, email, password })
      if (!user) {
        return res.status(404).json({ error: "No user found " })
      }
      return res.status(200).json({ user })
    } catch (error) {
      return next(error)
    }
  },

  loginUser: async (req, res, next) => {
    try {
      const { email, password } = req.body
      if (!email || !password) {
        return res.status(400).json({ message: "Email and password are must" })
      }
      if (!validator.isEmail(email)) {
        return res.status(400).json({ message: "Invalid email" })
      }
      const user = await User.findOne({ email })
      if (!user) {
        return res.status(404).json({ message: "This email does not exist" })
      }
      if (!user.confirmPassword(password)) {
        return res.status(401).json({ message: "Incorrect password" })
      }
      const token = auth.signToken({ userId: user._id })

      res.status(200).json({ user, token })
    } catch (error) {
      return next(error)
    }
  },

  identifyUser: async (req, res, next) => {
    try {
      const userId = req.user.userId
      const user = await User.findOne({ _id: userId })
      if (!user) {
        return res.status(500).json({ error: "No user found " })
      }
      return res.status(200).json({ user })
    } catch (error) {
      return next(error)
    }
  },

  getUser: async (req, res, next) => {
    try {
      const user = await User.findById(req.params.id)
      if (!user) {
        return res.status(404).json({ message: "User not found" })
      }
      return res.status(200).json({ user })
    } catch (error) {
      return next(error)
    }
  },

  listUsers: async (req, res, next) => {
    try {
      const users = await User.find({})
      if (!users) {
        return res.status(404).json({ message: "No users found" })
      }
      return res.status(200).json({ users })
    } catch (error) {
      return next(error)
    }
  },

  updateUser: async (req, res, next) => {
    try {
      const userData = {
        username: req.body.username,
        email: req.body.email,
        password: req.body.password,
      }
      const user = await User.findByIdAndUpdate(req.params.id, userData, {
        new: true,
      })
      if (!user) {
        return res.status(400).json({ error: "No user found" })
      }
      return res.status(200).json({ user })
    } catch (error) {
      return next(error)
    }
  },

  deleteUser: async (req, res, next) => {
    try {
      const user = await User.findByIdAndDelete(req.params.id)
      if (!user) {
        return res.status(200).json({ error: "No user found" })
      }
      return res.status(200).json({ user })
    } catch (error) {
      return next(error)
    }
  },

  getUserPosts: async (req, res) => {
    try {
      const user = await User.findById(req.params.id).populate("posts")
      if (!user) {
        return res.status(400).json({ error: "No user" })
      }
      return res.status(200).json({ userPosts: user.posts })
    } catch (error) {
      console.log(error)
    }
  }
}

postController.js

const Post = require("../models/Post")
const User = require("../models/User")
const mongoose = require("mongoose")

module.exports = {
  newPost: async (req, res, next) => {
    try {
      const postData = {
        title: req.body.title,
        description: req.body.description,
        user: req.user.userId,
      }
      const post = await Post.create(postData)
      if (!post) {
        return res.status(404).json({ error: "No post found" })
      }
      const user = await User.findById(req.user.userId)
      user.posts.push(post._id) //pushing post document's objectid to the user's posts array
      user.save().then(() => {
        return res.status(200).json({ user })
      })
    } catch (error) {
      return next(error)
    }
  },

  listPosts: async (req, res, next) => {
    try {
      const posts = await Post.find({}).populate("user")
      if (!posts) {
        return res.status(404).json({ error: "No posts found" })
      }
      return res.status(200).json({ posts })
    } catch (err) {
      return next(error)
    }
  },

  getPost: async (req, res) => {
    try {
      const post = await Post.findById(req.params.id)
      if (!post) {
        return res.status(404).json({ message: "No post found " })
      }
      return res.status(200).json({ post })
    } catch (error) {
      return next(error)
    }
  },

  editPost: async (req, res, next) => {
    try {
      const postData = {
        title: req.body.title,
        description: req.body.description,
      }
      const post = await Post.findByIdAndUpdate(req.params.id, postData, {
        new: true,
      })
      if (!post) {
        return res.status(404).json({ message: "No post found " })
      }
      return res.status(200).json({ post })
    } catch (error) {
      return next(error)
    }
  },

  deletePost: async (req, res) => {
    try {
      const post = await Post.findByIdAndDelete(req.params.id)
      if (!post) {
        return res.status(200).json({ error: "No post found" })
      }
      await User.updateOne(
        { _id: mongoose.Types.ObjectId(post.user) },
        { $pull: { posts: mongoose.Types.ObjectId(post._id) } }
      )
      res.status(200).json({ post })
    } catch (error) {
      console.log(error)
    }
  },
}
```
\$\endgroup\$

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.