DEV Community

João Hencke
João Hencke

Posted on

Validating schema with Yup!

Do you think validate types in JavaScript is boring?
Have you heard about Yup? It's an amazing JavaScript lib to validate schemas!

Let's imagine:

We have a list products endpoint, which takes the page number and limit as arguments from querystring

//productApi.js
const { Router } = require('express');
const productController = require('./controller');

const router = new Router();

module.exports = app => app.use('/products', router);

router.get('/', (req, res, next) => {
  const { page, limit } = req.query;

  if (isNaN(page) || isNaN(limit)) return res.status(400).end();

  productController.list({ page: Number(page), limit: Number(limit) })
    .then(products => res.json(products))
    .catch(error => res.status(400).json({ error }));
}
Enter fullscreen mode Exit fullscreen mode

The problem is: page and limit can be undefined and... anything else... it's javascript baby.

A very efficient way is to create a middleware to validate your params using Yup.

//validate.js
const yup = require('yup');

module.exports = ({ shape, path = 'query' }) => async (req, res, next) => {
  const schema = yup.object().shape(shape);

  try {
    const validData = await schema.validate(req[path]);
    req.validData = validData;
    return next();
  } catch (error) {
    return res.status(400).json({ error });
  }
};
Enter fullscreen mode Exit fullscreen mode

After then, use on route

//productApi.js
const { Router } = require('express');
const yup = require('yup');
const validate = require('./validate');
const productController = require('./controller');

const router = new Router();

module.exports = app => app.use('/products', router);

router.get(
  '/',
  validate({
    shape: {
      page: yup.number().default(0),
      limit: yup.number().default(15),
    }
  }),
  (req, res, next) => {
    productController
      .list(req.validData)
      .then(products => res.json(products))
      .catch(error => res.status(400).json({ error }));
  },
);
Enter fullscreen mode Exit fullscreen mode

Of course you can create complex schemas with Yup. It works as you need.

I hope it helps someone!

Top comments (10)

Collapse
 
rafanami profile image
Rafael Nami

Awesome post João, thanks!
I've used Joi but it's pretty sluggish depending on the validation rules you need to implement. I've stumbled across github.com/icebob/fastest-validator, which is my go-to Javascript "spec/schema" definition package at the moment.

Collapse
 
joaohencke profile image
João Hencke

Glad to read this!
I never heard about fastest-validator before. Thanks for share! Seems to be really fast 😱

Collapse
 
slidenerd profile image
slidenerd

how are you using this with express routes? middleware? mind sharing how your middleware looks

Collapse
 
merthod profile image
Merthod

You need to make a manual middleware passing the schema, just as a custom middleware for joi/yup/express-validator, etc.

Other middlewares (like celebrate) might add extra features like distinct body, query and params validation.

Collapse
 
gledsonafonso profile image
Gledson Afonso

That implementation using on routes was really cool! I have seen people using Joi, though, never heard of Yup. Gonna check it out later.

Collapse
 
joaohencke profile image
João Hencke

Yup's api/style was inspired by Joi!

Collapse
 
ygorgasparin profile image
Ygor Gasparin

Awesome tips bro!

Collapse
 
meguiluzortiz profile image
Manuel Eguiluz

Thanks, it helps me a lot.

Collapse
 
slidenerd profile image
slidenerd

nice post! how do you validate query params and body at the same time using your middleware

Collapse
 
merthod profile image
Merthod

You'd need to create a custom middleware, validate, sanitize and pass everything over to the route, or you can search for middlewares in npm.