Saturday, September 3, 2022

NodeJS | APIs JOI Validation

 Validation of the data is an interesting topic. Nowadays, it becomes a necessity for public web services or APIs. There are different situations available when we need to perform different types of checks for validating requests as well as responses that won't break our code.

Joi is a popular npm module for validating the request that comes to the server. It allows us to create blueprints of Javascript objects that ensure that we process and ultimately accept accurate data.

In this tutorial, we'll be going to learn about how we can use Joi validation in NodeJS and ExpressJS.

What is Joi?

According to npm documentation:
It is the most powerful schema description language and data validator for JavaScript.

Getting Started

Follow the step-by-step guide to learn about how we can apply Joi validation on our NodeJs and ExpressJS app:

Step 1:- Let's create a directory name nodejs_joi_validation and initialize the project using the npm command.
  • mkdir nodejs_joi_validation
  • cd nodejs_joi_validation
  • npm init -y

 

Step 2:- Installing needed npm Modules

For creating the server I'm using the express module, for data "body-parser" and for validation joi. And I'm going to install "nodemon" module for self-starting the server if any modification will happen in any file.

Let's install them using the following command:

npm install express joi body-parser --save

npm install nodemon --save-dev

After installing these npm modules. Your "package.json" file will look like this.

{
  "name": "nodejs_joi_validation",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {    "body-parser": "^1.20.0",
    "express": "^4.18.1",
    "joi": "^17.6.0"
  },
  "devDependencies": {
    "nodemon": "^2.0.19"
  }
}


Step 3:- Setting up the Server

After installing all needed npm modules. Let's first set up the server. For setting up the server, let's first create a server file name "index.js". You can create a file using the following command and by using the widgets.

touch index.js

After creating the server file. Let's create a server with an error handler. For creating the server you may copy the following code:

const express = require('express')
const app = express()const bodyParser = require('body-parser')
const PORT = process.env.PORT || 3000
app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); // error handler app.use(function (err, req, res, next) { return res.status(500).send({ error: true, message: err }); }); app.listen(PORT, () => { console.log(`Server is running at ${PORT} port`) })

Let's run the server by running the following command:

npm start

After starting the server your server may produce the following output:

[nodemon] 2.0.19
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node index.js`
Server is running at 3000 port


CONGRATULATIONS.....You've successfully set up your Server.

Step 4:- Create APIs routes and controller

Before applying the Joi validation, we first create APIs for that. Let's create two folder name routes and a controller at the root location. Make a file in both folders' names "index.js". With the help of the following command:

mkdir Routes Controller
cd Routes
touch index.js
cd ../Controller
touch index.js

Let's first import the route's "index.js" file into our server file i.e., "index.js" just before the error handler.

...app.use('/', require('./Routes'))

After importing the routes file into our server. Let's create some routes and their corresponding controllers.

The following code is for the routes "index.js" file.

const router = require('express').Router()
const Controller = require('../Controller')

router.get('/', Controller.homePageController)
router.post('/create-new', Controller.createNewDataController)

module.exports = router

The following code is for the controller "index.js" file.

const homePageController = async (req, res, next) => {
    try {
        res.status(200).send('Welcome to Home Page!!')
    } catch (error) {
        next(error)
    }
}

const createNewDataController = async (req, res, next) => {
    try {
        res.status(200).json({
            bodyData: req.body
        })
    } catch (error) {
        next(error)
    }
}

module.exports = {
    homePageController,
    createNewDataController
}

Following are the outputs when you hit these two requests:










Step 5:- Joi Validation set up

After the successful setup of our server. Let's create some validation for the post request which may validate the data.

For that scenario, I'm going to take an example of the request object in which the properties are of different data types which may be as follows:

  1. name: String with min 3 words and a maximum of 30 words which cannot be empty which means it's compulsory
  2. birthyear: Integer with mini 1970 and maximum 2012
  3. designation: String which can be null means it's not necessary for data 


For that scenario, let's create a folder named "validations" inside which we create the "index.js" file which may hold all validations at the root level by the following command:

mkdir validationscd validationstouch index.js

Inside that "index.js", we're going to create a validation for that post request according to that scenario.

Let's first import the Joi module and with the help of that module create some validations.

Well, Joi supports all sorts of primitives as well as Regex and can be nested to any depth. Let’s list some different constructs it supports:


  • string, this says it needs to be of type string, and we use it like so Joi.string()
  • number, Joi.number() and also supporting helper operations such as min() and max(), like so Joi.number().min(1).max(10)
  • required, we can say whether a property is required with the help of the method required like so Joi.string().required()
  • any, this means it could be any type, usually, we tend to use it with the helper allow() that specifies what it can contain, like so, Joi.any().allow('a')
  • optional, this is strictly speaking not a type but has an interesting effect. If you specify for example prop : Joi.string().optional. If we don't provide props then everybody's happy. However if we do provide it and make it an integer the validation will fail
  • array, we can check whether the property is an array of said strings, then it would look like this Joi.array().items(Joi.string().valid('a', 'b')
  • regex, it supports pattern matching with RegEx as well like so Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/)

Joi provides validate function which helps us for validating the data according to the schema.

Following are the code for that validations:

const Joi = require('joi')

const newDataValidation = data => {
    const dataSchema = Joi.object().keys({
        name: Joi.string().required().min(3).max(30),
        birthyear: Joi.number().integer().min(1970).max(2012),
        designation: Joi.string().allow(null, '')
    })

    return dataSchema.validate(data)
}

module.exports = {
    newDataValidation
}


After creating the validation, let's import that validation function into our controller's "index.js" file for validating the request data.

This function may provide an error object which may contain any error which occurred at the time of validation otherwise it'll be false.

const { newDataValidation } = require('../validations')...
const createNewDataController = async (req, res, next) => { try { const { error } = await newDataValidation(req.body) if (error) { res.status(400).json({ error: true, message: error.details[0].message }) } res.status(200).json({ bodyData: req.body }) } catch (error) { next(error) } }

...


Screenshots













You can also visit my GitHub repository nodejs_joi_validation for that code in case you got any type of issues.


I recommend you to visit Joi documentation for more details.