hapi.jsjoi

Joi validation set default as empty object


I'm running into an issue (or what I believe to be one) with Joi validation. I'm trying to assign a value to a non-existent key if it's been passed as part of the request body.

So for example:

parameters: Joi.object().keys({
  keyA: Joi.string().allow('').allow(null).default(null),
  keyB: Joi.object().keys({
    b1: Joi.string(),
    b2: Joi.string(),
    b3: Joi.object().keys({
      b3_1: Joi.string(),
      b3_2: Joi.string(),
      b3_3: Joi.string()
    })
  }).default({}),
  keyC: Joi.object().keys({
    c1: Joi.number(),
    c2: Joi.number(),
    c3: Joi.boolean(),
    c4: Joi.boolean()
  }).default({}),
  keyD: Joi.object().keys({
    d1: Joi.number(),
    d2: Joi.number()
  }).default({}),
  keyE: Joi.object().keys({
    e1: Joi.number()
  }).default({}) 
}).allow(null)

So to be specific if I were to pass in:

{
  keyA: "foo",
  keyD: {
    d1: 21.9,
    d2: 21.1
  },
  keyE: {
    e1: 42
  }
}

I would get this in return

{
  keyA: "foo",
  keyB: {},
  keyC: {},
  keyD: {
    d1: 21.9,
    d2: 21.1
  },
  keyE: {
    e1: 42
  }
}

With :eyes: on the empty objects. What am I missing with the Joi.default() method? Am I overextending what Joi is meant for?


Solution

  • I'll start by pointing out that the schema in your question isn't valid JavaScript, you've closed a few too many brackets before declaring the rule for keyC. I'll assume this is simply a formatting error with the question and your actual schema is currently valid.

    Secondly, there's nothing wrong with how you've declared your defaults.. it works just fine. I'll assume it's the way you're validating the schema which is the problem.

    Try running this. I've mimicked the validation method in the docs for default().

    const schema = Joi.object().keys({
        keyA: Joi.string().allow('').allow(null).default(null),
        keyB: Joi.object().keys({
            b1: Joi.string(),
            b2: Joi.string(),
            b3: Joi.object().keys({
                b3_1: Joi.string(),
                b3_2: Joi.string(),
                b3_3: Joi.string()
            })
        }).default({}),
        keyC: Joi.object().keys({
            c1: Joi.number(),
            c2: Joi.number(),
            c3: Joi.boolean(),
            c4: Joi.boolean()
        }).default({}),
        keyD: Joi.object().keys({
            d1: Joi.number(),
            d2: Joi.number()
        }).default({}),
        keyE: Joi.object().keys({
            e1: Joi.number()
        }).default({})
    }).allow(null);
    
    Joi.validate({
        keyA: "foo",
        keyD: {
            d1: 21.9,
            d2: 21.1
        },
        keyE: {
            e1: 42
        }
    }, schema, (err, value) =>
    {
        if (err)
            throw err;
    
        console.log(value);
    });
    

    I get this in the console:

    {
        keyA :'foo',
        keyD: {
            d1: 21.9,
            d2: 21.1
        },
        keyE: {
            e1: 42
        },
        keyB: {},
        keyC: {}
    }
    

    The keys are unlikely to look ordered like your expected output, but that shouldn't matter as object keys are not ordered anyway.