---
# System prepended metadata

title: Joi Validator

---

---
title: "Joi Validator"
disqus: JBeanny
---

By: Yim Sotharoth

Using joi validator
===

## Table of Contents

[TOC]

## Installation

:::info
_firstly create a node project_
```bash=
$ npm init --y
```

_I named my folder as joi so I cd in my folder_

> In joi folder I installed joi library with the following command

```bash=
$ npm install joi
```

> I also installed a few more libraries such as: mongoose,dotenv,and express

**Note that I used MongoDB as database**
:::

## Folder structure

> This is the folder structure for this testing project

![](https://i.imgur.com/kbY77pH.png)



## Config

> In `config` folder I created a `index.js` file to grab the environment variables with the following code:

```javascript!
require("dotenv").config({ path: ".env.local" });

module.exports = {
  DATABASE_URL: process.env.DATABASE,
  PORT: process.env.PORT || 8080,
};
```

:::info
You can create a .env file and store those sensitive data. In my case I named my env file as `.env.local`
:::

## Create Global Error Handler

> In `utils` I created a `GlobalErrorHandler.js` with the following code:

```javascript!
const GlobalErrorHandler = (error, req, res, next) => {
  res.status(error.status || 500).json({
    success: false,
    status: "Failed !",
    message: error.message,
  });
};

module.exports = GlobalErrorHandler;
```

:::info
By using GlobalErrorHandler we can reduce our try-catch blocks
:::

## Connect to database and config the server

> In `app.js` 

```javascript!
const express = require("express");
const app = express();

app.use(express.json());

//global error handler
const GlobalErrorHandler = require("./src/utils/GlobalErrorHandler");

app.get("/", (req, res) => {
  res.send("Hello from Metaphorlism");
});

app.use(GlobalErrorHandler);

module.exports = app;
```

> In `index.js`

```javascript!
const app = require("./app");
const mongoose = require("mongoose");
const { PORT, DATABASE_URL } = require("./src/config");

// connect to database
mongoose.set("strictQuery", false);
mongoose
  .connect(DATABASE_URL)
  .then(() => console.log("Connected to database . . ."))
  .catch((err) => console.log(err));

// start the server
app.listen(PORT, () => {
  console.log(`SERVER IS RUNNING ON PORT: ${PORT}`);
});
```

## Model

> In `models` folder I created a `students.model.js` file with the following code:

```javascript!
const mongoose = require("mongoose");

const studentSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
  },
  age: {
    type: Number,
    required: true,
  },
  grade: {
    type: Number,
    required: true,
  },
  gender: {
    type: String,
    required: true,
    enum: ["Male", "Female", "Others"],
  },
  details: {
    type: String,
  },
});

const Student = mongoose.model("Student", studentSchema);

module.exports = Student;
```

## Controller

> In `controllers` I created a `students.controller.js` file with the following code:

```javascript!
const StudentModel = require("../models/students.model");

class Student {
  async createStudent(req, res) {
    const student = await StudentModel.create(req.body);

    res.status(201).json({
      status: "Success",
      message: "Created Successfully",
      student,
    });
  }
}

module.exports = new Student();
```

## Error Messages

> In `utils` I created a `ErrorMessages.js` file with the following code:

```javascript!
// response status code
const status = {
  BAD_REQUEST: 400,
  UNAUTHORIZED: 401,
  NOT_FOUND: 404,
  SERVER_ERROR: 500,
};

// not found error
class NotFoundError extends Error {
  constructor(message) {
    super(message);
    this.status = status.NOT_FOUND;
  }
}

// bad request error
class BadRequestError extends Error {
  constructor(message) {
    super(message);
    this.status = status.BAD_REQUEST;
  }
}

// unauthorized request error
class UnauthorizedError extends Error {
  constructor(message) {
    super(message);
    this.status = status.UNAUTHORIZED;
  }
}

module.exports = { BadRequestError, NotFoundError, UnauthorizedError };
```

:::info
The purpose of creating this error classes is just for handling the error messages
:::

## Middleware

> In `middlewares` I created a `bodyValidator.js` file with the following code:

```javascript!
const {
  BadRequestError,
  NotFoundError,
  ServerError,
} = require("../utils/ErrorMessages");

const bodyValidator = (schema) => {
  const Validator = (req, res, next) => {
    const { error } = schema.validate(req.body);
    if (error) {
      next(new BadRequestError(error.details[0].message));
    }
    next();
  };
  return Validator;
};
module.exports = bodyValidator;
```

:::info
Here is where we are going to implement the joi library
:::
## Validator

> In `validators` I created a `studentSchema.js` file with the following code:

```javascript!
const Joi = require("joi");

const studentSchema = Joi.object({
  name: Joi.string()
    .required()
    .messages({ "any.required": "Student name is required" }),
  age: Joi.number()
    .required()
    .messages({ "any.required": "Student age is required" }),
  grade: Joi.number()
    .required()
    .messages({ "any.required": "Student grade is required" }),
  gender: Joi.string().valid("Male", "Female", "Others").required().messages({
    "any.required": "Gender is required",
    "any.only": "Invalid gender type",
  }),
  details: Joi.string().empty(""),
});

module.exports = studentSchema;
```

## Route

> In `routes` I created a `students.routes.js` file with the following code:

```javascript!
const express = require("express");
const router = express.Router();

//controller
const StudentController = require("../controllers/students.controller");

//validator
const bodyValidator = require("../middlewares/bodyValidator");
const studentSchema = require("../validators/studentSchema");

router
  .route("/")
  .post(bodyValidator(studentSchema), StudentController.createStudent);

module.exports = router;
```

## Call student route into app.js

> Let's modify `app.js` a little

```javascript!
const express = require("express");
const app = express();

app.use(express.json());

//global error handler
const GlobalErrorHandler = require("./src/utils/GlobalErrorHandler");

//routes
const STUDENT_ROUTES = require("./src/routes/students.routes");

app.get("/", (req, res) => {
  res.send("Hello from Metaphorlism");
});

app.use("/students", STUDENT_ROUTES);

app.use(GlobalErrorHandler);

module.exports = app;
```

## Testing

> Input with the correct format

![](https://i.imgur.com/nLWfH6y.png)

> Input with the incorrect format

![](https://i.imgur.com/pRSPHbF.png)


> Project Repository : https://github.com/metaphorlism/npm-libraries/tree/npm-joi

### Contact Us

- :mailbox: yimsotharoth999@gmail.com
- [GitHub](https://github.com/metaphorlism) 
- [Facebook Page](https://www.facebook.com/Metaphorlism)
- [Instagram: Metaphorlism](https://www.instagram.com/metaphorlism/)
