Validation with Yup

2 Min Read — In React, testing, Yup

What is Yup?

Yup is a JavaScript object schema validator.

Lets understand the above definition with an example. Consider everday common feature of login form with fields "username" and "password". Before submitting form we want to verify that user has entered all fields. A Valid object should look something like shown below

const loginObj = {
username: "abcd",
password: "123456"
};

What we have here is expected schema for login form. And we know fields "username" and "password" are mandatory, so we have validations on those fields.

Once we have object schema and validation, we can use "Yup" lib to verify if any given object satisfies the schema and validations

How It works?

Simplest way to use Yup

  1. Define object schema and its validation
  2. Create validator object using Yup with expected schema and validation
  3. Use Yup utility function "validate" to verify if object are valid(satisfies schema and validations)

Lets take a case in which we need to work with "car" objects with properties as shown below.

const car = {
year: 200,
model: "Hyundai",
engine: "Petrol",
price: 2000
};

For a car object to be valid following criteria should be met

  1. "model" and "engine" property should be of type string
  2. "year" and "price" property should be of type number
  3. Except "price" all the other properties are mandatory

The validator object

Now we will create validator object for "car" object

const yup = require("yup");
const yupObject = yup.object().shape({
price: yup.number(),
year: yup.number().required(),
model: yup.string().required(),
engine: yup.string().required()
});

I think above code is pretty self explanatory. It is similar to how we define proptypes in react.

Verify

Next validate "car" object created above using "validate" method on yup object.

yupObject
.validate(car)
.then(function(value) {
console.log(value); // returns car object
})
.catch(function(err) {
console.log(err);
});

"validate" method returns promise which returns same object if the passed object is valid, in case of invalid "car" object it returns error object with message.

const car = {
year: 200,
model: "Hyundai"
};
yupObject.validate(car); //ValidationError: engine is a required field

Chaining of validations

We can chain validation as shown below

const yup = require("yup");
const schemaValidatorObject = yup.object().shape({
year: yup
.number()
.required()
.min(2000)
.max(2018)
});

Custom Validation

Many times we need to go beyond simple validation provided by library and write custom validation.

Ex: Lets say if we want to test whether beverge is tea or not

let customValidation = yup.object().shape({
beverage: yup
.string()
.test("is-tea", "${path} is not tea", value => value === "tea")
});
await customValidation.validate({ beverage: "tea" });

Async Validation

To make a validation async return a promise that resolves true or false or a ValidationError

let orderTea = yup.object().shape({
bevrage: yup
.string()
.test(
"is-tea",
"${path} is not tea",
async value => (await value) === "tea"
)
});
await orderTea.validate({ bevrage: "coffee" }); // returns Error

Note: In order to allow asynchronous custom validations all (or no) tests are run asynchronously. A consequence of this is that test execution order cannot be guaranteed

Dependent Validation

Suppose validation on a field is dependent on value of other field. In example shown below we want tea field to be mandatory only if isMorning is true.

const schema = object({
isMorning: boolean(),
tea: string().when("isMorning", {
is: true,
then: yup.required()
})
});

Similarly we can add validation which is dependent on multiple fields by passing an array of strings

const schema = yup.object().shape({
isMorning: yup.boolean(),
isSunday: yup.boolean(),
coffee: yup.number().when(["isMorning", "isSunday"], {
is: (isMorning, isSunday) => {
//any complex calulation
return isMorning && !isSunday;
},
then: yup.number().required()
})
});

Yup no coffee on sunday morning

Yup in Formik

It very simple to use Yup with formik. We just need to pass the validator object to formik's validationSchema option. All the Yup's validation errors are transformed into formik state variables. Which can be used to show error messages.

import { Formik } from "formik";
import * as Yup from "yup";
const SignupSchema = Yup.object().shape({
email: Yup.string()
.email("Invalid email")
.required("Required")
});
<Formik
initialValues={{
email: ""
}}
validationSchema={SignupSchema}
>
...
</Formik>;

Ending Note

I hope this gives you good understanding of how Yup works and helps you in getting started. You can try above mentioned examples here(https://runkit.com/pratik14/yup-examples)