How to perform custom validation in your Express.js app (Part
How to perform custom validation in your Express.js app (Part-2)
In the previous post, I showed how to get started with input validation in an express.js application. I used the express-validator module and discussed its important features with implementation.
If you haven’t checked that out, please go read the first post
So now let’s get started. In part 2 of this tutorial, you will learn how to perform custom validation in an Express.js app.
What you can achieve with custom validation
- It can be used to verify the existence of the entity in your database.
- Also to test if a certain value exists in an array, object, string etc.
- If you want to change the data format itself.
And a lot more…
The express-validator library provides a custom
method which you can use to do all sorts of custom validations
Implementation of a custom validator uses the chain method .custom(). It takes a validator function.
Custom validators return Promises to show an async validation or throw
Now I will show you examples of the above custom validation use cases.
Check if the entity exists in your database
An important one which I use on day to day basis — and I guess you will be using to verify an entity against a database
For example, if someone requests to update their name, you’d use it for a basic PUT
request /api/users/:userId
.
To make sure that the user should exist in our database, I created a function to check against the DB.
param('userId').exists().isMongoId().custom(val => UserSchema.isValidUser(val))
isValidUser()
is a static function which will make an async call to the database and find if the user exists or not.
Let’s write a static function in mongooseSchema
:
UserSchema.statics = {
isValid(id) {
return this.findById(id)
.then(result => {
if (!result) throw new Error('User not found')
})
},
}
As we cannot trust the userId
sent by the client based on its format only, we need to make sure it is a real account.
Verify against certain values in Array or Object
For example, if you want to apply a rule on a username that it must have a character @
.
So in your POST
request of user creation or while updating, you can do something like this:
body('username', 'Invalid Username').exists().isString().isLowercase().custom(val => { if (val.indexOf('@') !== -1) return true
return false}),
Remember: Always return a boolean value from the callback of .custom()
function. Otherwise your validation might not work as desired.
As you can see, we can do all these validations including async in middleware itself instead of doing them in a controller
Change input data format
The library has a Sanitization feature where custom sanitization is performed using customerSanitizer()
.
I used it to change the string of comma separated values to an array of strings.
For example, we have a doctor database. Someone wants to get only doctors who are cardiologists and psychiatrists.
We have stored both of these specializations as a type
in our database.
A simple GET
request will look like this:
GET /api/doctors?type=cardiologists,psychiatrist
Now in mongodb
we can use the $in
operator to search for multiple values of a property.
A basic database query can be like:
Doctors.find({ type: {
$in: ['cardiologists', 'psychiatrist']
}})
This will give you all cardiologists and psychiatrists.
From GET
query:
req.query = {
type: "cardiologists,psychiatrist"
}
As you can see in req.query
, you will get a property type
whose type is a string
.
With the help of.customSanitizer()
we are able to convert a string into an array of strings.
At the validation level:
const commaToArray = (value = '') => value.split(',')
sanitizeQuery('type').customSanitizer(commaToArray),
Now we can directly feed it to the database query to the $in
operator.
What if I want to apply some rules on all items in an array or keys in objects?
Body:
{ items:[ {_id: 'someObjectId', number: '200'}, ... ]}
Wildcards
Wildcard is one of the great features of this module. It allows you to iterate over an array of items or object keys and validate each item or its properties.
The *
character is also known as a wildcard.
Imagine I want to validate all the _id, number
of items.
check('items.*._id').exists().isMongoId().custom(val => ItemSchema.isValid(val)), //similar to isValidUser()
sanitize('items.*.number').toInt()
There you have it — an introduction to input validation using the express-validator module
If you encounter any problems, feel free to get in touch or comment below.I would be happy to help :)
Don’t hesitate to clap if you considered this a worthwhile read!