21. Data Sanitization & Schema Validation

  • "Data sanitization in MongoDB" refers to the process of defining rules within your MongoDB schema to clean and filter user input data before storing it in the database, preventing potential malicious code or invalid data from being inserted

  • mostly POST and PATCH API somehow interact with data by inserting the data either by registration or updation where we can perform strict checks.

  • we perform some check and validation inside schema defined also

  • we can see here how mongoose define schema type and according to that you can keep check on fields.

  • Some of schema types are:-

    required: true/false:- to make any field mandatory

    unique: true/false:- to make any field unique and any duplicate value not allowed in field

    default:value :- to make default value of any field property.

    lowercase:true/false:- to convert string in lowercase or uppercase

    trim:true/false :- to trim down extra space within string

    minLength / maxLength : integer :- to fix the maximum and minimum length of string to be entered in string

    min / max: value :- it is same as minLength and maxLength but it is for Number data type

    validate() :- this function is used to add custom validation function to any field

      gender: {
          type: String,
          validate(value) {
            if (!["male", "female", "others"].includes(value)) {
              throw new Error("gender invalid");
            }
          },
        },
    

    but during updation using findByIdAndUpdate() we have to add an attribute as “runValidators:true“

    timestamps:true :- to add time and date at which the data is altered in database it is added in schemas directly

  • validating email is not easy job so we need a package provided by npm known as express-validator to validate email

  • after doing “npm i express-validator“ use validator with validate function

  • API level validation is mostly applied on patch and post request

      //schema validation
      const mongoose = require("mongoose");
      const validator = require("validator");
      const userSchema = new mongoose.Schema(
        {
          firstName: {
            type: String,
            minLength: 4,
            maxLength: 25,
          },
          lastName: {
            type: String,
          },
          emailId: {
            type: String,
            required: true,
            unique: true,
            validate(value) {
              if (!validator.isEmail(value)) {
                throw new Error("invalid email address");
              }
            },
          },
          password: {
            type: String,
            required: true,
            validate(value) {
              if (!validator.isStrongPassword(value)) {
                throw new Error(
                  "Password must be at least 8 characters long, and must contain at least"
                );
              }
            },
          },
          city: {
            type: String,
          },
          age: {
            type: String,
            min: 10,
            max: 30,
          },
          gender: {
            type: String,
            validate(value) {
              if (!["male", "female", "others"].includes(value)) {
                throw new Error("gender invalid");
              }
            },
          },
          photoURL: {
            type: String,
          },
          skills: {
            type: [],
          },
          about: {
            type: String,
            default: "This is default value",
          },
        },
        {
          timestamps: true,
        }
      );
      const User = mongoose.model("User", userSchema);
      module.exports = User;
    
      //app.js
      const express = require("express");
      const app = express();
      const connectDB = require("./config/database"); //getting DB connection
      const port = 3000;
      const User = require("./models/user"); //getting User model
      app.use(express.json());
      app.get("/user", async (req, res) => {
        const userEmail = req.body.emailId;
        try {
          const user = await User.find({ emailId: userEmail });
          if (user.length === 0) {
            res.status(404).send("user list empty");
          } else {
            res.send(user);
          }
        } catch (err) {
          res.status(400).send("error saving the data:- " + err.message);
        }
      });
      app.delete("/user", async (req, res) => {
        const userID = req.body.userId;
        try {
          const user = await User.findByIdAndDelete({ _id: userID });
          res.send("deleted success");
        } catch (err) {
          res.status(400).send("Error;- " + err.message);
        }
      });
      app.post("/user", async (req, res) => {
        const user = new User(req.body);
        try {
          await user.save();
          res.send("data saved success");
        } catch (err) {
          res.status(404).send("error:- " + err.message);
        }
      });
      app.patch("/user", async (req, res) => {
        const userId = req.body.userId;
        const data = req.body;
    
        try {
          const ALLOWED_UPDATES = ["firstName", "about", "gender", "age", "city"];
          const isUpdateAllowed = Object.keys(data).every((k) =>
            ALLOWED_UPDATES.includes(k)
          );
          if (!isUpdateAllowed) {
            throw new Error("update not allowed");
          }
          if (data?.skills.length > 10) {
            throw new Error("skills cannot be more than 10");
          }
          const user = await User.findByIdAndUpdate({ _id: userId }, data, {
            returnDocument: "before", //this returnDocument is added to know the data before or after updation
            runValidators: true, //this is used to validate the data
          });
          console.log(user); //to know before/after the data updation.
          res.send("updated successfully");
        } catch (err) {
          res.status(400).send("Error:- " + err.message);
        }
      });
      connectDB()
        .then(() => {
          console.log("connected to DB");
          app.listen(port, () => {
            console.log(`Server is running on port ${port}`);
          });
        })
        .catch((err) => {
          console.error("Not connected to DB");
        });