Learn how to validate user input in your Node.js application using Express Validator the right way—clean, maintainable, and scalable.
✅ Why Request Validation Matters
In real-world applications, you must validate user input to:
-
Ensure correct data is received.
-
Prevent server crashes or database errors.
-
Enhance user experience with meaningful error messages.
🗂 Step 1: Update the User Model
Let’s define a complete schema for our User
model that includes validation requirements like required fields
and default timestamps.
src/models/User.ts
import * as mongoose from ‘mongoose’; import { model } from ‘mongoose’; const userSchema = new mongoose.Schema({ email: { type: String, required: true }, password: { type: String, required: true }, username: { type: String, required: true }, created_at: { type: Date, default: new Date(), required: true }, updated_at: { type: Date, default: new Date(), required: true } }); export default model(‘users’, userSchema);
🧪 Step 2: Bad Approach – Manual Validation (NOT RECOMMENDED)
Here’s an example of manual validation in the controller. It works but becomes messy and repetitive as your app grows.
UserController.ts
export class UserController { static signup(req, res, next) { const { username, email, password } = req.body; if (!username) return next(new Error(‘Username is required’)); if (!email) return next(new Error(‘Email is required’)); if (!password) return next(new Error(‘Password is required’)); // Save user logic here… } }
❌ Problem:
-
Violates DRY principle (Don’t Repeat Yourself).
-
Clutters your controller.
-
Not scalable for larger forms.
✅ Step 3: Install Express Validator
Let’s use a better approach.
Run in terminal:
npm install –save express-validator
🧱 Step 4: Create a Validator Layer
We’ll now create a validators
folder and define rules for user registration.
src/validators/UserValidator.ts
import { body } from ‘express-validator’; export class UserValidators { static signup() { return [ body(‘username’, ‘Username is required’).isString(), body(’email’, ‘Valid email is required’).isEmail(), body(‘password’, ‘Password must be at least 6 characters long’).isLength({ min: 6 }), ]; } }
🎯 You can even add custom validation using
.custom()
if needed later.
🔁 Step 5: Connect Validator to Router
Now we apply these validation rules before the controller logic runs.
UserRouter.ts
import { UserValidators } from ‘../validators/UserValidator’; import { UserController } from ‘../controllers/UserController’; getRoutes() { this.router.post(‘/signup’, UserValidators.signup(), UserController.signup); }
🧠 Step 6: Handle Validation Results in Controller
Finally, in the controller, check if validation failed using validationResult
.
UserController.ts
import { validationResult } from ‘express-validator’; import User from ‘../models/User’; export class UserController { static signup(req, res, next) { const errors = validationResult(req); if (!errors.isEmpty()) { const firstError = errors.array()[0].msg; return next(new Error(firstError)); } const { username, email, password } = req.body; const newUser = new User({ username, email, password }); newUser.save() .then(user => res.status(201).json(user)) .catch(err => next(err)); } }
✅ Final Test
Use Postman:
-
POST
http://localhost:5000/api/user/signup
-
Body:
x-www-form-urlencoded
-
username: testuser
-
email: [email protected]
-
password: secret123
-
You’ll receive validation errors if any fields are missing or invalid.
🧩 Summary
Step | Description |
---|---|
1️⃣ | Define schema with required fields |
2️⃣ | Avoid manual validation in controller |
3️⃣ | Use Express Validator for clean rules |
4️⃣ | Centralize all validation in a validator file |
5️⃣ | Handle errors using validationResult |
6️⃣ | Return readable error messages |