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"); });