44

I want to make async validation with formik and validationschema with yup but i can't find the example or demo.

Day's Night
  • 613
  • 2
  • 8
  • 12

5 Answers5

43
const validationSchema = Yup.object().shape({
    username:
        Yup.string()
            .test('checkDuplUsername', 'same name exists', function (value) {
                return new Promise((resolve, reject) => {
                    kn.http({
                        url: `/v1/users/${value}`,
                        method: 'head',
                    }).then(() => {
                        // exists
                        resolve(false)
                    }).catch(() => {
                        // note exists
                        resolve(true)
                    })
                })
            })
})

Yup provides asynchronous processing through the test method.
(kn is my ajax promise function)
have a nice day.

이석규
  • 439
  • 4
  • 4
  • 1
    Any idea on how to do multiple validations for the same field? For example, if the name is required and it must be unique – tsinat Mar 24 '20 at 21:08
  • @tsinat simply chain it - e.g., `Yup.string.required('Username is required').test(...)` – mariachi Mar 30 '20 at 00:46
  • 2
    Doing this results in the following for me: `Error: Validation test of type: "exists" returned a Promise during a synchronous validate. This test will finish after the validate call has returned` – Chris Edwards Jun 04 '20 at 15:00
  • you need to return also the `kn.http` or you will loose the async chain – quirimmo Jun 16 '20 at 08:33
11

Actually, it can be simplified a bit


const validationSchema = Yup.object().shape({
    username: Yup.string().test('checkEmailUnique', 'This email is already registered.', value =>
        fetch(`is-email-unique/${email}`).then(async res => {
            const { isEmailUnique } = await res.json()

            return isEmailUnique
        }),
    ),
})
Tomas Dohnal
  • 1,815
  • 2
  • 16
  • 16
5

You can use async/await with yup custom validator

let field = yup.string().test(
'test-id',
'error message in case of fail',
 async function validateValue(value){
  try{
    
     // validation logic
     return false; // or true as you see fit

  } catch(error){

  }
});

return true for the values you accept

return false for the values you reject

Make sure you always return a boolean, or add a finally block if you don't have that guarantees yourself.

Louay Al-osh
  • 3,177
  • 15
  • 28
4

For example I am using fake promise, It can be done as follow:

  const Schema = yup.object().shape({
      password: yup
   .string()
  .test("validPassword","Password requires one special character",
  function (value) {
    return new Promise((resolve) => {
      setTimeout(() => {
        if (
          /^[0-9A-Za-z]*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?][0-9a-zA-Z]*$/.test(
            value
          )
        ) {
          resolve(true);
        } else {
          resolve(false);
        }
      }, 100);
    });
  }
 ),
});
    
H S W
  • 6,310
  • 4
  • 25
  • 36
0

Here is how to async validate with API call:

const validationSchema = Yup.object().shape({
  username: Yup.string().test('checkDuplUsername', 'same name exists', function (value) {
    if (!value) {
      const isDuplicateExists = await checkDuplicate(value);
      console.log("isDuplicateExists = ", isDuplicateExists);
      return !isDuplicateExists;
    }
    // WHEN THE VALUE IS EMPTY RETURN `true` by default
    return true;
  }),
});

function checkDuplicate(valueToCheck) {
  return new Promise(async (resolve, reject) => {
    let isDuplicateExists;

    // EXECUTE THE API CALL TO CHECK FOR DUPLICATE VALUE
    api.post('url', valueToCheck)
    .then((valueFromAPIResponse) => {
      isDuplicateExists = valueFromAPIResponse; // boolean: true or false
      resolve(isDuplicateExists);
    })
    .catch(() => {
      isDuplicateExists = false;
      resolve(isDuplicateExists);
    })
  });
}
Rahul Gupta
  • 9,775
  • 7
  • 56
  • 69
  • 1
    I'm curious to know whether this was tested. One obvious problem to me, before I even attempt to try this, is that you have a ``await`` in a function that's not marked with ``async``. That's already a "compiler" error right there. – Kibonge Murphy Aug 30 '22 at 06:20