Yup: No method / option to declare an attribute as optional

Created on 19 Feb 2016  路  4Comments  路  Source: jquense/yup

As far as i can tell, there is no method that allows to specify an attribute as optional.

My issue is the following

const subSchema = {
  foo: yup.string().required()
}
const schema = yup.object().shape({
  optional: yup.object().shape(subSchema),
  required: yup.required().shape(subSchema)
})

When i validate schema, omitting optional will fail, because optional.foo is required.

It seems kinda limiting that i cannot control optional (and in my logic, the required() method appended to any attribute in the shape should control if its required, not the required methd inside the subSchema).

A i just missing the point here, or is the not possible at the moment?

Most helpful comment

Fields are optional by default, but when not strict mode, the value is cast when validating which will use the _default_ value when the value is empty so:

const subSchema = {
  foo: yup.string().required()
}

const schema = yup.object().shape({
  optional: yup.object().shape(subSchema),
  required: yup.object().shape(subSchema).required()
})

schema.isValid({ required: { foo: 'foo' } }, { strict: false }) // false
schema.isValid({ required: { foo: 'foo' } }, { strict: true })  // true

object schema have built in defaults where they construct an object from their shape, so

yup.object({ 
  foo: string().default('bar') 
})
.default() // => { foo: 'bar' }`.

The reason is that the first case above fails, is that optional, being empty, uses its default() which is: {} now that the value isn't empty foo gets validated, is missing and fails.

if you set the default to undefined (i.e. remove it) it would work like you expect.

const schema = yup.object().shape({
  optional: yup.object().shape(subSchema).default(undefined),
  required: yup.object().shape(subSchema).required()
})

schema.isValid({ required: { foo: 'foo' } }) // true

Joi has a option to validate without using default values, that I have been thinking of adding as well...

All 4 comments

Fields are optional by default, but when not strict mode, the value is cast when validating which will use the _default_ value when the value is empty so:

const subSchema = {
  foo: yup.string().required()
}

const schema = yup.object().shape({
  optional: yup.object().shape(subSchema),
  required: yup.object().shape(subSchema).required()
})

schema.isValid({ required: { foo: 'foo' } }, { strict: false }) // false
schema.isValid({ required: { foo: 'foo' } }, { strict: true })  // true

object schema have built in defaults where they construct an object from their shape, so

yup.object({ 
  foo: string().default('bar') 
})
.default() // => { foo: 'bar' }`.

The reason is that the first case above fails, is that optional, being empty, uses its default() which is: {} now that the value isn't empty foo gets validated, is missing and fails.

if you set the default to undefined (i.e. remove it) it would work like you expect.

const schema = yup.object().shape({
  optional: yup.object().shape(subSchema).default(undefined),
  required: yup.object().shape(subSchema).required()
})

schema.isValid({ required: { foo: 'foo' } }) // true

Joi has a option to validate without using default values, that I have been thinking of adding as well...

That makes sense.. :)

I solved it by applying a custom test

optional: object().test('valid object', 'not valid', value => {
  if (value === undefined) {
    return true;
  } else {
    return object().shape(subSchema).validate(value);
  }
})

But the default method is better..

Thanks for clarifying..

@jquense Consider adding something about default(undefined) on object to the documentation. Just ran into this myself and luckily found this ticket =)

makes sense, PRs welcome! :)

Was this page helpful?
0 / 5 - 0 ratings