So far so good, now let's move to another important topic: Validation.
Validation
Well, you'll start thinking now, what he will use for validation?, exactly as you thought, we'll do it from scratch xD, why? because its fun.
Why Validation?
Any application will receive data from the user, and that data will be stored in the database, and that data will be used to perform some action, so it is important to validate that data, to ensure that it is correct, and that it is not malicious
.
How it works
The scenario will be like this:
- We attach the route handler to the route.
- If the route has a
validation
static property, then the request handler will start making the validation. - If the validation fails, then the request handler will return an error.
- If the validation succeeds, then the request handler will be executed.
We'll do a simple validator that we can attach to the handler function the controller function
a static variable we'll call it validation
this will contain a rules
object and we'll use it like this:
// src/apps/users/controllers/create-user.ts
export default function createUser(request) {
const { name, email } = request.body;
return {
name,
email
}
}
createUser.validation = {
rules: {
name: ['required', 'string'],
email: ['required', 'email'],
}
};
And that it!
Now let's start create our simple validator.
Request handler
If you remember we created earlier a Request class that handle the request, which has an execute
method that calls our handler.
That executer we'll check inside it if the handler has a validation
property, if so then we'll get it and start validating the request inputs in these rules.
If the validation passes, then we'll call the handler, if not we'll throw an error.
// src/core/http/request.ts
/**
* Execute the request
*/
public async execute() {
if (this.handler.validation) {
const validationResult = new Validator(this, this.handler.validation);
validationResult.scan();
if (!validationResult.passes()) {
return this.response.status(422).send(validationResult.errors());
}
}
return await this.handler(this, this.response);
}
We checked if the handler has a validation
property, if so then we call the Validator
class to validate the request inputs, this class will receive all inputs and the rules.
Validator class
Now let's make the validator class, create validator
folder inside src/core
and create index.ts
file inside it.
// src/core/validator/index.ts
import { Request } from "core/http/request";
export default class Validator {
/**
* Validation errors
*/
protected errorsList: any = [];
/**
* Constructor
*/
public constructor(
protected readonly request: Request,
protected readonly rules: any,
) {
//
}
/**
* Scan all the rules and validate the request
*/
public scan() {}
/**
* Determine if the validation passes
*/
public passes() {
return this.errorsList.length === 0;
}
/**
* Determine if the validation fails
*/
public fails() {
return !this.passes();
}
/**
* Get errors list
*/
public errors() {
return this.errorsList;
}
}
Here we added errorsList
as an array that will contain all errors list, the constructor receives the request and the rules, and we added scan
method that will scan all the rules and validate the request, and we added passes
and fails
methods that will determine if the validation passes or fails.
Now let's start the validation process.
If you're wondering why we're using
readonly
because it do what is says, we don't want to modify it, we just want to read it.If you're wondering why we're using
protected
because we may make it in the future to be extended.
Validation process
First we'll get all the inputs from the request that needs to be validated, and we'll loop over the rules and validate each input.
So we only need to get the input values for these rules, let's make a new method called only
in the request class that will return the input values for these rules.
// src/core/http/request.ts
import { only } from "@mongez/reinforcements";
// class Request {
// ..
/**
* Get only the given keys from the request
*/
public only(keys: string[]) {
return only(this.all(), keys);
}
We used only utility to get only these given keys from the request.
Now let's head back to the validator class and get the inputs that needs to be validated.
// src/core/validator/index.ts
/**
* Scan all the rules and validate the request
*/
public scan() {
// get the request data for the rules inputs
const inputValues = this.request.only(Object.keys(this.rules));
// loop through the rules
for (const input in this.rules) {
// get the value for the input
const inputValue = inputValues[input];
// get the rules for the input
const inputRules = this.rules[input];
// Create a new rule handler to validate the input
const rule = new Rule(input, inputValue, inputRules);
// if the rule validation fails
if (rule.validate().fails()) {
// then add the rule errors to the errors list
this.errorsList.push(rule.errors());
}
}
}
I've put comments per each line i wrote above, first we'll get the input values directly from the request so we don't make multiple calls to the request class, then we made a loop over the rules (Remember it is an object not an array) so we used for.in
loop to get the input as as the key, next we got the following data:
- The input value
- The input rules
Then we created a new Rule
class to validate the input, and we called the validate
method on it, if the validation fails then we'll add the errors to the errors list.
Rule class
Now let's make the rule class, create rule.ts
file inside src/core/validator
folder.
// src/core/validator/rule.ts
export default class Rule {
/**
* Errors list
*/
protected errorsList: any = [];
/**
* Constructor
*/
public constructor(
protected readonly input: string,
protected readonly value: any,
protected readonly rules: any,
) {
//
}
}
We'll stop at this point of the tutorial, and we'll continue in the next part.
Conclusion
In this article we covered the concept behind how we would implement the validation process, and we made a simple validator that can validate the request inputs.
🎨 Project Repository
You can find the latest updates of this project on Github
😍 Join our community
Join our community on Discord to get help and support (Node Js 2023 Channel).
🎞️ Video Course (Arabic Voice)
If you want to learn this course in video format, you can find it on Youtube, the course is in Arabic language.
💰 Bonus Content 💰
You may have a look at these articles, it will definitely boost your knowledge and productivity.
General Topics
- Event Driven Architecture: A Practical Guide in Javascript
- Best Practices For Case Styles: Camel, Pascal, Snake, and Kebab Case In Node And Javascript
- After 6 years of practicing MongoDB, Here are my thoughts on MongoDB vs MySQL
Packages & Libraries
- Collections: Your ultimate Javascript Arrays Manager
- Supportive Is: an elegant utility to check types of values in JavaScript
- Localization: An agnostic i18n package to manage localization in your project
React Js Packages
Courses (Articles)
Top comments (0)