DEV Community

Cover image for Simplify Validation with Joi in Just 4 Steps ๐Ÿš€
Abayomi Ogunnusi
Abayomi Ogunnusi

Posted on

2

Simplify Validation with Joi in Just 4 Steps ๐Ÿš€

Say goodbye to long if-else validation blocks! With the Joi npm package, you can achieve clean and efficient validation in just 4 simple steps.

Before diving into the steps, let's see how validations can be written using if-else.

const validateCreateCareer = (req, res, next) => {
  const { title, description, teamType, location, skills, salary, jobLevel, postingDate, employmentType, experienceRequired, remote } = req.body;

  if (!title) {
    return res.status(400).json({ status: 'error', message: 'Title is required.' });
  }

  if (!description) {
    return res.status(400).json({ status: 'error', message: 'Description is required.' });
  }

  if (!teamType || !['Engineering', 'Marketing', 'Sales'].includes(teamType)) { // Example teamType values
    return res.status(400).json({ status: 'error', message: 'Invalid or missing teamType.' });
  }

  if (!Array.isArray(location) || location.some((loc) => typeof loc !== 'string')) {
    return res.status(400).json({ status: 'error', message: 'Location must be an array of strings.' });
  }

  if (!Array.isArray(skills) || skills.some((skill) => typeof skill !== 'string')) {
    return res.status(400).json({ status: 'error', message: 'Skills must be an array of strings.' });
  }

  if (salary !== undefined && typeof salary !== 'number') {
    return res.status(400).json({ status: 'error', message: 'Salary must be a number.' });
  }

  next(); // Proceed if all validations pass
};

export default validateCreateCareer;

Enter fullscreen mode Exit fullscreen mode

Drawbacks of if-else Validation

๐Ÿ’ฃ Verbosity: The code becomes lengthy and repetitive.
๐Ÿ’ฃ Error-Prone: Higher risk of missing edge cases or typos.
๐Ÿ’ฃ Maintenance: Harder to maintain or extend as requirements grow.

Now let's look at the JOYOUS way

๐Ÿ› ๏ธ Step 1: Install the Joi Package

Run the following command to install Joi:

npm i joi
Enter fullscreen mode Exit fullscreen mode

๐Ÿ› ๏ธ Step 2: Configure Joi Validation Middleware
Create a reusable validation middleware to streamline your validation process:

import Joi from 'joi';
import { Request, Response, NextFunction } from 'express';

const validate = (schema: Joi.ObjectSchema<object>) => {
  return (req: Request, res: Response, next: NextFunction) => {
    const { error } = schema.validate(req.body);
    const valid = error == null;

    if (valid) {
      next();
    } else {
      const { details } = error;
      const message = details.map((i) => i.message).join(',');

      const newMessage = message.replace(/"/g, '');
      res.status(422).json({
        status: 'error',
        message: newMessage,
      });
    }
  };
}; 

export { validate };
Enter fullscreen mode Exit fullscreen mode

๐Ÿ› ๏ธ Step 3: Create a Joi Validator File
Define your validation schemas in a dedicated file:

    createCareerSchema: Joi.object().keys({
        title: Joi.string().required(),
        description: Joi.string().required(),
        teamType: Joi.string().valid(...Object.values(TeamType)).required(),
        location: Joi.array().items(Joi.string()).required(),
        skills: Joi.array().items(Joi.string()).required(),
        salary: Joi.number(),
        jobLevel: Joi.string().valid("Junior", "Mid-Level", "Senior").required(),
        postingDate: Joi.date().iso().required(),
        employmentType: Joi.string().valid("Full-Time", "Part-Time", "Contract").required(),
        experienceRequired: Joi.number().integer().min(0).required(),
        remote: Joi.boolean().default(false),
    }),
};

export default careersSchema;
Enter fullscreen mode Exit fullscreen mode

๐Ÿ› ๏ธ Step 4: Use It in Your Routes
Integrate the validation middleware in your Express routes:

import { validate } from './middleware/validate';
import careersSchema from './validators/careersSchema';
import CareersController from './controllers/CareersController';

router.patch(
  "/careers/:id/update", 
  validate(careersSchema.updateCareerSchema), 
  CareersController.updateCareer
);

router.post(
  "/careers", 
  validate(careersSchema.createCareerSchema), 
  CareersController.createCareer
);

export default router;
Enter fullscreen mode Exit fullscreen mode

โœ… Test It Out!
Try making API requests with missing or invalid fields. The middleware will automatically handle errors and return a user-friendly response. ๐ŸŽ‰

Image description

With these 4 steps, your validation process becomes concise, efficient, and easy to maintain. Happy coding! ๐Ÿš€

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

๐Ÿ‘‹ Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay