Tutorial

How to Handle Form Inputs Efficiently with Express-Validator in ExpressJs

Published on January 19, 2024
How to Handle Form Inputs Efficiently with Express-Validator in ExpressJs

The author selected OWASP Foundation to receive a donation as part of the Write for DOnations program.

Introduction

Modern web developers always deal with inputs, whether they be web forms, file uploads, or any other input on their websites. Therefore, it becomes essential for them to ensure that the inputs they receive from users are legit and harmless.

With advancements in web development, attackers have developed more and have found ways of exploiting websites from different aspects, such as form inputs. Attacks like Cross-Site Scripting (XSS) and SQL Injection have become more common and harmful than ever before. Therefore, any developer needs to ensure that the data they receive from a user is non-malicious or sanitized to ensure the integrity of their web application and server.

In this tutorial, you will learn how to use the Express-Validator package of JavaScript to validate and sanitize user inputs in web forms to ensure data consistency and server security.

Prerequisites

To understand this tutorial properly, you should have the following setup:

  1. Install Node Js with version 14.x or higher on your system. You can use this DO tutorial to install the latest Node Js version on your system.

  2. You should know how to code in JavaScript.

  3. You should have Express JS version 4.x or higher installed on your system. You can use this to set up an Express server.

After meeting these requirements, you can continue with the tutorial.

Importance of input validation in Web Development

Input validation and Sanitization is a key task for a developer for various reasons mentioned below:

  1. Prevention from Injection Attacks: Consider a scenario where your application is vulnerable to SQL Injection attacks. This vulnerability arises due to the poor handling of SQL code during user authentication through an authentication form. An attacker can exploit this by passing some malicious SQL code instead of user credentials and gaining access to the server, which is game over for the application.

  2. Data Integrity and Consistency: When user input is validated, it creates consistency in data being stored in servers, thus making it complicated to work with the data. For example, if a user can send text data in input for age, it creates inconsistency in the data stored in the server.

  3. Data Compatibility: The data type must be consistent when data is used at various endpoints in a big organization. For instance, if users can enter garbage data instead of a proper email in their email credentials, it could cause complications when the organization needs to contact the user.

  4. Enhanced User Experience: When inputs are validated, a developer can create logic to send appropriate and immediate feedback to users, allowing them to correct the invalid input they provided. This enhances the overall User Experience.

There are many such reasons to ensure that, as a developer, you handle the inputs in your web forms and websites efficiently and securely. In the following sections, you will learn how to create validation logic for your form inputs using the Express-Validator package in an Express Js app.

Terminology used in input validation and sanitization

Validator – A validator is a function that takes input and performs certain checks based on some criteria.

Sanitizer – A sanitizer is a function used to modify or cleanse input data to ensure that it is secure and adheres to required formats.

Validation Chain – A validation chain in Express-Validator is a sequence of validators or sanitizers applied on an input. For example, assume that you have a form where you want users to enter their email and, to keep your data in the database consistent, you want no whitespaces to be allowed in the input (at left or right ends). You can use a validation chain like .isEmail() to achieve this.trim() [You will learn about these in a later section]. This will first check whether the input is an email; if it is email data, then the trim() sanitizer will remove whitespaces from both ends of the input.

Installing Express-Validator and integrating it with an Express Server

Now, you will learn to implement input validation and sanitization techniques in the following sections of this tutorial. Firstly, you will set up an npm project and then install Express Js, Express-Validator, and other dependencies required to follow the tutorial.

  1. To create an Express server, first, you need to create an npm project. Firstly, open a terminal and type the following commands:

    cd <project directory>
    npm init
    
  2. Then, you will be asked for inputs asking information about the application; you can either enter the specific details or continue pressing ‘Enter.’ Now, create an index.js file in the project folder; this will be the entry point for the server. Lastly, you must install the Express Js package to create an Express server. This can be done with the following command.

    npm install express
    
  3. You now have the Express Js installed in your project. The next task is to install Express-Validator, which can be done with the following command.

    npm install Express-Validator
    
  4. We have satisfied basic dependencies till now; however, you can install nodemon in your project, which is useful to keep a Node Js app running even if some error occurs. Type the following command to install it.

    npm install nodemon
    

We now have installed all requirements and can start working on the server and input validation in forms. This project will be the base structure used in all the later sections, where each section explains a different topic.

The next section explains how Express-Validator works behind the scenes and how you can use it in forms to perform input validations on various fields.

Basic form validation techniques in Express-Validator

Express-Validator is a combination of middleware provided by the Express JS module and the Validator.js module, which provides validators and sanitizers for string data types. Express-Validator provides the functionality to validate input data by using a validation chain.

In this section, you will learn to use the validators in Express-Validator using the Node Js project set up in the previous section. For this, you will create a route in Express Server that allows users to sign up for a web application with their credentials (name, email, password). Then, you will create middleware to validate the inputs every time a user signs up for your server.

Open the index.js file and type the following code into it.

index.js
  1. const express = require("express");
  2. const app = express();
  3. const { body, validationResult } = require("express-validator");
  4. // Express.js middleware to use JSON objects
  5. app.use(express.json());
  6. app.post(
  7. "/signup",
  8. // using validation to verify valid inputs (MIDDLEWARE)
  9. [
  10. [
  11. body("name").notEmpty(),
  12. body("email").isEmail(),
  13. body("password").notEmpty(),
  14. ],
  15. ],
  16. async (req, res) => {
  17. const errors = validationResult(req);
  18. if (!errors.isEmpty()) {
  19. return res.status(400).json({ errors: errors.array() });
  20. }
  21. res.status(200).json({success:'Successful Sign Up!'})
  22. }
  23. );
  24. // Server Listening at port 3000
  25. const port = 3000;
  26. app.listen(port, () => {
  27. console.log(`Listening at http://localhost:${port}`);
  28. });

Here, we import the Express Js and then create an Express app. Then, we use JavaScript destructing to import the body and validationResult functions from the Express-Validator.

Info The body() method is used to create validation chains for validating and selecting input data from request payloads( req) from users, such as data sent by a POST request. The validationResult() method stores the result of a validation chain of an HTTP request as a JavaScript object. If this object is empty, it implies that the payload has passed all validation tests; if not, it stores information about the payload and the criteria it did not satisfy.

Then, we use the JSON middleware of Express J to work with JSON objects.

Finally, we create an Express route using the HTTP - POST (You can work with any other type of request, such as GET, PUT, etc.) request. The route we have created here represents a route to a signup form on a web server. The form takes input using client-side HTML, and the server handles it by accessing the input fields of the web form using the body of HTML DOM.

The body() method of the Express-Validator fetches the values of HTML components having the name attribute same as the argument of the body() method; i.e., body(“password”) will fetch the value of HTML input component having the name attribute as password.

Then, on these values, you can use the validators provided by Express-Validator. In this example, we have used two validators, isEmail() and notEmpty(). These validators determine whether the input is email and not empty, respectively. If the input does not match the criteria of the validator(s), the Express-Validator will throw an error as an object in the form of the validationResult(). However, if the input matches the criteria of the applied validators, the validationResult() object will be empty. This is then used inside the function definition of the ‘/signup’ route to create a simple check using if statement. Suppose the validationResult() array is not empty. In that case, an error with response code 400 is sent to the client. Otherwise, in this example, a message of successful sign-up is sent to the client (This is just for exemplary purposes; you can perform any task, such as storing the input data in a database, using the input credentials to authenticate a user, etc.). Then, we host the server on localhost at port 3000.

These basic validators were used in this example; however, you can use any other validator offered by the Express-Validator package. In the following table, you can find some commonly used validators, which can be used in the same manner as isEmail() and notEmpty().

Validator Usage
isDate Checks if the Input is a Date object.
isEmpty Checks if the Input is an Empty string.
isHash(algorithm) Checks if the Input is a hash. The argument takes the hashing algorithm such as MD5, SHA, etc.
isJWT Checks if the Input is a JWT(JavaScript Web Token).
isURL Checks if the Input is a URL.
isBoolean Checks if the Input is Boolean(True or False).
isNumeric Checks if the Input is of numeric data type.
isAlphanumeric Checks if the Input is Alphanumeric.
isInt Checks if the Input is an Integer type.
isDecimal Checks if the Input is in Base Decimal.
isFloat Checks if the Input is a Floating Point Number.

Now, in the following section, you will learn how to validate file inputs to make file uploads through your form (such as a photograph or a signature) secure and controlled.

Handling file input validation in web forms (Optional)

In the previous section, you learned how to use the Express-Validator to validate inputs generally passed to web forms. In this section, you’ll learn how to handle file inputs and validate them before uploading them to a server to avoid uploading malicious files on your server. In addition to this security benefit, you can put constraints on the file input size, ensuring no large files fill up your server.

We will use the multer package of Node Js to handle file uploads using forms. You can use this extensive DO tutorial to understand how multer works, Uploading files with multer in Node.js and Express. Now, Express-Validator does not provide specific functionality for file input handling; however, you can combine the multer library as an extension to Express-Validator for handling file input validation for your web forms. Before using multer, you must install the package in your Node Js project, which can be done by following the command.

cd <project folder>

npm install multer

Now, you will see how to integrate multer with your Express server using Express-Validator. In the following code, you will implement multer and Express-Validator and put some constraints on uploaded files.

index.js
  1. const express = require("express");
  2. const app = express();
  3. const { body, validationResult } = require("express-validator");
  4. const multer = require("multer");
  5. // Express.js middleware to use JSON objects
  6. app.use(express.json());
  7. // CREATING MIDDLEWARE USING MULTER TO HANDLE UPLOADS
  8. // creating a storage object for multer
  9. const storage = multer.diskStorage({
  10. // providing the destinations for files to be stored in server
  11. destination: "./uploads/",
  12. });
  13. // defining file storage to local disk and putting constraints on files being uploaded
  14. const upload = multer({
  15. storage: storage,
  16. limits: { fileSize: 1*1024*1024 }, // file size in bytes
  17. // you can add other constraints according to your requirement such as file type, etc.
  18. });
  19. app.post(
  20. "/fileUpload",
  21. // input validation for files to ensure only a single file is uploaded in one request
  22. upload.single("fileUpload"),
  23. // using validation to verify valid inputs
  24. [
  25. body("fileDescription").notEmpty(),
  26. // you can add as many validators as you require
  27. ],
  28. async (req, res) => {
  29. const errors = validationResult(req);
  30. if (!errors.isEmpty()) {
  31. return res.status(400).json({ errors: errors.array() });
  32. }
  33. const file = req.file;
  34. // perform any other tasks on the file or other form inputs
  35. res.status(200).json({ success: "Successful Sign Up!" });
  36. }
  37. );
  38. // Server Listening at port 3000
  39. const port = 3000;
  40. app.listen(port, () => {
  41. console.log(`Listening at http://localhost:${port}`);
  42. });

Here, we have defined the necessary imports and the Express JSON middleware to work with JSON objects over a network. Then, we define the storage-server for multer to work. The example is explained in detail below:

  1. First, we define a storage category. Multer provides both disk storage and memory storage(buffer). In this example, we have used disk storage to store uploaded files on a server’s local disk instead of wasting memory.

  2. When using disk storage, it is necessary to provide the directory location where uploaded files will be stored. This can be done using the destination keyword, which takes the path as a value. Here, we have used an uploads folder in the project directory itself.

  3. After this, we create an upload object which handles the upload of files. This calls the multer import and takes a JavaScript object as input. This JavaScript object contains various constraints/validations to be satisfied before storing the input file on disk. Storage is a necessary argument that will take the storage object as input, defined before this.

  4. We have added another validation using the limits option to ensure no file is greater than 1 MB. Note that it counts size in bytes.

Info: You can make other validations/checks in the limits object according to your requirement.

  1. Then, we create an Express route to handle file upload and add a middleware upload.single(), ensuring that only one file is uploaded in one request. It takes the input field named fileUpload from HTML DOM as the required argument.

  2. After this, we add Express-Validator middleware, as explained in the previous section.

  3. Lastly, we create the logic to handle the route and check for any errors in input validation.

  4. You can access the uploaded file(s) from your route logic from the req.file object.

Here, you learned how to handle file input validation using Multer and integrate it with the Express-Validator validation middleware. In addition, you can add many other advanced or custom validation methods in Multer and Express-Validator. In the next section, you will learn how to sanitize input values, which is necessary to prevent attacks like SQL Injection.

Sanitization of form inputs

So far, you have learned how to perform input validations on data and file input. Now, you will extend that knowledge by learning how to sanitize (validated) inputs. Express-Validator provides many sanitizers from the Validator.js library.

For explaining sanitizers, we will use a similar approach as the ‘Basic form validation techniques in Express-Validator and add sanitizers in the route.

index.js
  1. const express = require("express");
  2. const app = express();
  3. const { body, validationResult } = require("express-validator");
  4. // Express.js middleware to use JSON objects
  5. app.use(express.json());
  6. app.post(
  7. "/sanitizedInput",
  8. // sanitizing inputs
  9. [
  10. [
  11. body("name").notEmpty().trim(),
  12. body("email").isEmail().trim(),
  13. body("dob").toDate(),
  14. ],
  15. ],
  16. async (req, res) => {
  17. const errors = validationResult(req);
  18. if (!errors.isEmpty()) {
  19. return res.status(400).json({ errors: errors.array() });
  20. }
  21. // remaining logic for your route
  22. res.status(200).json({success:'Successful Sign Up!'})
  23. }
  24. );
  25. // Server Listening at port 3000
  26. const port = 3000;
  27. app.listen(port, () => {
  28. console.log(`Listening at http://localhost:${port}`);
  29. });

You create another Express server by importing necessary packages and using the Express JSON middleware to handle JSON objects. Then, you will create a route to handle sanitized input (/sanitizedInput) and write the route logic.

Again, you need to add Express-Validator middleware. Here, we use three input fields: name, email, and dob. First, we check if the name is not empty using notEmpty() and then apply the trim() sanitizer on it, which removes whitespaces from both ends of the input value. Similarly, for the email input field, we first check whether it is a valid email using isEmail() and then apply trim() sanitizer to remove whitespaces from both ends.

In the dob input field, we use the toDate() sanitizer (without any validator) to convert the input string into a date object. If the string is not an actual date, toDate() will return a null value.

After that, you will perform the check to ensure that there are no errors stored in the validationResult() object and can continue with the rest of the logic for your route.

Note: Using multiple validators and sanitizers on a single input, as done with body("name").notEmpty().trim(), creates a chain of validators/sanitizers. Such a chain or sequential use of validators/sanitizers creates a validation chain.

There are plenty more sanitizers available with Express-Validator, such as blacklist(), whitelist(), etc. You can use them according to your requirements.

Conclusion

In this tutorial, you learned how to effectively handle form inputs on your server. You built servers using the Express-Validator library that used input validation and sanitization techniques. You can build upon this knowledge and extend your input validation further by using different validators and sanitizers provided by the same library.

Express-Validator and Multer both allow you to create custom validators, which you can try as an exercise to increase your productivity in complex projects.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar

Technical Content Engineer


Default avatar

Manager, Developer Relations


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.