Going ProfessionalExtra· 40 min read

Validating & Sanitizing Input

Never trust data from the outside world. Reject bad input cleanly — before it reaches your database — with a validation library.

What you will learn

  • Explain why server-side validation is non-negotiable
  • Validate request bodies with a validation library
  • Return clear 400 errors listing what was wrong

Why validate on the server at all?

Your React form might check that a field is filled in — but a determined user (or a buggy script, or an attacker) can send a request straight to your API with tools like Postman, skipping the front-end entirely. The browser’s checks never run. So your server is the only place you fully control, and it must assume every incoming request could be wrong, missing fields, or even malicious.

Validation means checking that incoming data is shaped the way you expect (the right fields, the right types, sensible lengths) and rejecting it early if not. Sanitization is the cleanup cousin — trimming stray spaces, stripping dangerous characters — so only tidy data reaches your database.

  1. A request arrives at a route that expects, say, a text field.
  2. A validation step inspects the body before your main logic runs.
  3. If anything is wrong, you stop immediately and reply 400 (Bad Request) with a message naming the problem.
  4. Only fully valid requests reach the code that saves to the database.

The manual way (and why it does not scale)

You already saw a tiny hand-written check in the error-handling lesson: if (!req.body.text) return res.status(400).... That works for one rule, but real endpoints need many — required, correct type, minimum and maximum length, valid email format. Writing all that by hand for every route quickly becomes a tangle. A validation library lets you declare the rules once, clearly.

Validation with express-validator

express-validator is a popular library that plugs in as middleware. You list the rules for each field, and it collects any failures for you to inspect. Install it first:

Terminal: install express-validator
npm install express-validator

Note: Output: added a few packages in 1s This adds express-validator to your project so you can require its body and validationResult helpers.

Now attach an array of rules to the route, then check the results at the top of the handler:

Declare rules, then check the result
const { body, validationResult } = require("express-validator");

app.post(
  "/tasks",
  [
    body("text").trim().notEmpty().withMessage("text is required")
      .isLength({ max: 200 }).withMessage("text must be 200 chars or fewer")
  ],
  (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      return res.status(400).json({ errors: errors.array() });
    }
    // safe to use req.body.text here — it passed every rule
    res.status(201).json({ text: req.body.text });
  }
);

Line by line: body("text") targets the text field of the request body. .trim() sanitizes it by removing surrounding spaces. .notEmpty() requires a value, and .isLength({ max: 200 }) caps its length — each with a friendly .withMessage(...). Those rules run as middleware. Inside the handler, validationResult(req) gathers any failures; if the list is not empty, we reply 400 with the details. If it is empty, every rule passed and the data is safe to save.

Note: Output (POST /tasks with an empty body): {"errors":[{"type":"field","msg":"text is required","path":"text","location":"body"}]} Output (POST /tasks with {"text":"Buy milk"}): {"text":"Buy milk"} The bad request never touches your database — it bounces with a clear, structured 400 telling the front-end exactly which field failed and why. The good request sails through.

Tip: Many teams instead use Zod or Joi, which describe the whole expected shape as a single schema object (for example z.object({ text: z.string().min(1).max(200) })). The idea is identical — declare the rules, reject anything that does not match — so once you understand one, the others read the same.

Watch out: Validation and authentication are different jobs. Validation asks "is this data well-formed?"; authentication (next lesson) asks "who is sending it, and are they allowed?". A real API needs both.

Q. Why is server-side validation essential even when your React form already validates?

Answer: Front-end checks can be skipped by sending requests directly to the API. The server must validate independently because it is the only layer you fully control.

✍️ Practice

  1. Add express-validator rules to a POST route requiring a non-empty text under 200 characters, and return a structured 400 on failure.
  2. Add a route that validates an email field with .isEmail() and test it with a bad address.

🏠 Homework

  1. Validate a "signup" body — require a name, a valid email, and a password of at least 8 characters — and return all failing rules at once.
Want to learn this with a mentor?

CodingClave runs guided, project-based training (28-day, 45-day & 6-month batches).

Explore Training →