Jump into concepts and practice - no test required
or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Custom Validation Rules in Express
📖 Scenario: You are building a simple Express server that accepts user registration data. You want to make sure the data is valid before saving it.
🎯 Goal: Create a custom validation rule in Express to check that the username is at least 5 characters long and the password contains at least one number.
📋 What You'll Learn
Create an Express app with a POST route /register
Add a custom validation function called isValidUsername that checks username length
Add a custom validation function called hasNumber that checks password contains a number
Use these custom validations in the route to validate incoming data
💡 Why This Matters
🌍 Real World
Custom validation rules help ensure user input is correct before processing, improving app reliability and user experience.
💼 Career
Backend developers often write custom validations in Express to enforce business rules and secure APIs.
Progress0 / 4 steps
1
Set up Express app and route
Create an Express app by importing express, calling express() to create app, and add a POST route /register with a callback that takes req and res.
Express
Hint
Remember to import express and create the app before defining routes.
2
Add custom validation functions
Add two functions: isValidUsername that takes username and returns true if its length is 5 or more, and hasNumber that takes password and returns true if it contains at least one digit.
Express
Hint
Use username.length >= 5 and a regular expression /\d/ to check for digits.
3
Use validations in the route
Inside the /register route, get username and password from req.body. Use isValidUsername(username) and hasNumber(password) to check validity. If either fails, respond with status 400 and message 'Invalid input'. Otherwise, respond with status 200 and message 'Registration successful'.
Express
Hint
Remember to parse JSON body with express.json() middleware before accessing req.body.
4
Start the server
Add app.listen to start the server on port 3000 and log 'Server running on port 3000' when it starts.
Express
Hint
Use app.listen(3000, () => { ... }) to start the server and log a message.
Practice
(1/5)
1. What is the main purpose of using custom() in Express validation?
easy
A. To format the response JSON
B. To automatically sanitize all inputs
C. To connect to the database
D. To create your own rules for checking input values
Solution
Step 1: Understand the role of custom()
The custom() method allows you to write your own validation logic beyond built-in checks.
Step 2: Identify the purpose in input validation
It is used to check inputs with rules you define, like checking a password strength or a special format.
Final Answer:
To create your own rules for checking input values -> Option D
Quick Check:
Custom validation = custom rules [OK]
Hint: Custom means you write your own check function [OK]
Common Mistakes:
Thinking custom() sanitizes inputs automatically
Confusing custom() with response formatting
Assuming custom() connects to databases
2. Which of the following is the correct syntax to add a custom validation rule using Express Validator?
easy
A. check('age').custom(value => { if(value < 18) throw new Error('Too young'); return true; })
B. check('age').custom(value => value < 18 ? true : false)
C. check('age').custom(value => { return false; })
D. check('age').custom(value => { throw 'Error'; })
Solution
Step 1: Review correct custom validation syntax
The function inside custom() should throw an error if validation fails and return true if it passes.
Step 2: Analyze each option
check('age').custom(value => { if(value < 18) throw new Error('Too young'); return true; }) throws an error when value is less than 18 and returns true otherwise, which is correct. check('age').custom(value => value < 18 ? true : false) returns true when value is less than 18, which is opposite logic. check('age').custom(value => { return false; }) always returns false, which fails validation. check('age').custom(value => { throw 'Error'; }) throws an error unconditionally, so it always fails.
Final Answer:
check('age').custom(value => { if(value < 18) throw new Error('Too young'); return true; }) -> Option A
Quick Check:
Throw error on fail, return true on pass [OK]
Hint: Throw error to fail, return true to pass [OK]
Common Mistakes:
Returning false instead of throwing error
Throwing error without condition
Returning true on invalid input
3. Given this code snippet, what will be the validation result if req.body.username is "abc"?
B. The condition should check for '.' instead of '@'
C. It should throw an error, not return it
D. No error, code is correct
Solution
Step 1: Understand error signaling in custom validation
Custom validators must throw an error to indicate failure, not return an Error object.
Step 2: Analyze the given code
The code returns new Error('Invalid email') instead of throwing it, so validation will not fail as expected.
Final Answer:
It should throw an error, not return it -> Option C
Quick Check:
Throw error to fail validation [OK]
Hint: Throw errors, don't return them in custom() [OK]
Common Mistakes:
Returning Error object instead of throwing
Checking wrong condition for email
Returning false instead of throwing error
5. You want to create a custom validation rule that checks if a password contains at least one uppercase letter, one number, and is at least 8 characters long. Which of these implementations correctly achieves this?
Step 1: Check each condition with proper error throwing
check('password').custom(value => {
if(!/[A-Z]/.test(value)) throw new Error('Missing uppercase');
if(!/\d/.test(value)) throw new Error('Missing number');
if(value.length < 8) throw new Error('Too short');
return true;
}) checks each condition separately and throws a specific error if it fails, returning true only if all pass.
Step 2: Compare other options for correctness
check('password').custom(value => {
if(value.length < 8) return false;
if(!/[A-Z]/.test(value)) return false;
if(!/\d/.test(value)) return false;
return true;
}) returns false instead of throwing errors, which is incorrect. check('password').custom(value => {
if(value.length < 8) throw 'Too short';
if(!/[A-Z]/.test(value)) throw 'Missing uppercase';
if(!/\d/.test(value)) throw 'Missing number';
return false;
}) throws string errors and returns false at the end, which breaks the rule of returning true on success. check('password').custom(value => {
if(value.length >= 8 && /[A-Z]/.test(value) && /\d/.test(value)) return true;
else return false;
}) returns false instead of throwing an error if conditions fail, which is incorrect.
Final Answer:
check('password').custom(value => {
if(!/[A-Z]/.test(value)) throw new Error('Missing uppercase');
if(!/\d/.test(value)) throw new Error('Missing number');
if(value.length < 8) throw new Error('Too short');
return true;
}) -> Option B
Quick Check:
Throw specific errors, return true if all pass [OK]
Hint: Throw specific errors for each fail, return true if all pass [OK]