Descriptive Hapi/Joi validation error

KoalaD picture KoalaD · Feb 26, 2015 · Viewed 10.9k times · Source

I've been trying to implement Joi in our node application (joi as standalone, not with hapi) and it seems to validate the schema properly but the error is always the same

[ValidationError: value must be an object] 
name: 'ValidationError',
details:
[ { message: 'value must be an object',
   path: 'value',
   type: 'object.base',
   context: [Object] } ],
_object:.....

I never get the specifics on which key it failed on and description of why it failed.

this is a sample schema I'm using:

exports.workersSchema =
{
workers: joi.array({
    id: joi.string().alphanum(),
    wID: joi.object({
        idValue: joi.string().alphanum()
    }),
    person: {
        governmentIDs: joi.array({itemID: joi.string().alphanum()}),
        legalName: joi.object({
            givenName: joi.string(),
            middleName: joi.string(),
            preferredSalutations: joi.array(
                {
                    salutationCode: {
                        longName: joi.string()
                    }

                }
            ),
            preferredName: joi.object().keys({
                FormattedName: joi.string()
            }),
        }),
        birthDate: joi.string().alphanum()
    }
})
}

And this is the json object I'm sending :

{"workers" : [        
        {
          "id" : "",
          "wID" : {
            "idValue" : ""
          },
          "person" : {
            "governmentIDs":[{
                "itemID": "asd" 
            }],
            "legalName":{
              "givenName" : "PA",
              "middleName" : "",
              "preferredSalutations" : [{
                "salutationCode" : {
                  "longName" : ""
                    }
              }],
              "preferredName" : {
                "FormattedName" : ""
              },
              "birthDate" : ""
        }]
}

What am i doing wrong here? I even tried to follow something on the blog and while the examples were showing detailed info I never got anything besides

"value must be an object"

It validates it correctly but when it sees a misfit value it just gives that error and nothing else.

Also, if you look at the 'wID' section it has a 'idValue' object but when I get rid of the idValue and just put a alphanum right on the wID key, it also passes the validation.

ps. When validating keys that are objects. Do I have to validate it with

key: Joi.object({
  a:Joi.string()
})

or can I just do?:

key: {
  a:Joi.string()
}

Thank you so much for the help!

Answer

Matt Harrison picture Matt Harrison · Feb 26, 2015

I think there's a couple of issues. First of all, make sure that the object you're validating against is indeed an object with a workers key. The validation seems to be suggesting that you're not providing an object for this base value (an array perhaps)?

Also in a few instances I think you're using the API incorrectly (e.g. joi.array(...) is not valid). I've modified your schema to work how I think you intended. If not, post a sample object and I'll amend.

var schema = {
    workers: Joi.array().required().includes({
        id: Joi.string().alphanum(),
        wID: {
            idValue: Joi.string().alphanum()
        },
        person: {
            governmentIDs: Joi.array().includes(Joi.string().alphanum()),
            legalName: {
                givenName: Joi.string(),
                middleName: Joi.string(),
                preferredSalutations: Joi.array().includes(Joi.string()),
                preferredName: {
                    formattedName: Joi.string()
                },
            },
            birthDate: Joi.string().alphanum()
        }
    })
};

Here's a valid object for that schema:

var goodExample = {
    workers: [
        {
            id: 'bhdsf78473',
            wID: {
                idValue: 'idvalue1'
            },
            person: {
                governmentIDs: ['id1', 'id2'],
                legalName: {
                    givenName: 'Johnny',
                    middleName: 'Michael',
                    preferredSalutations: ['sir', 'Dr'],
                    preferredName: {
                        formattedName: 'Sir Johnny Michael Smith'
                    }
                },
                birthDate: '2411986'
            }
        }
    ]
};

Here's an invalid one:

var badExample = {
    workers: [
        {
            id: 'bhdsf7^£$%^£$%8473',   // Here's the issue
            wID: {
            },
            person: {
                governmentIDs: ['id1', 'id2'],
                legalName: {
                    givenName: 'Johnny',
                    middleName: 'Michael',
                    preferredSalutations: ['sir', 'Dr'],
                    preferredName: {
                        formattedName: 'Sir Johnny Michael Smith'
                    }
                },
                birthDate: '2411986'
            }
        }, 
    ], 
};

Joi should give nice detailed output for Joi.assert(example, schema);:

$ node index.js

/.../node_modules/Joi/lib/index.js:121
            throw new Error(message + error.annotate());
                  ^
Error: {
  "workers": [
    {
      "wID": {},
      "person": {
        "governmentIDs": [
          "id1",
          "id2"
        ],
        "legalName": {
          "givenName": "Johnny",
          "middleName": "Michael",
          "preferredSalutations": [
            "sir",
            "Dr"
          ],
          "preferredName": {
            "formattedName": "Sir Johnny Michael Smith"
          }
        },
        "birthDate": "2411986"
      },
      "id" [1]: "bhdsf7^£$%^£$%8473"
    }
  ]
}

[1] workers at position 0 fails because id must only contain alpha-numeric characters
    at root.assert (/.../node_modules/Joi/lib/index.js:121:19)
    at Object.<anonymous> (/.../index.js:57:5)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:929:3

NOTE: This answer is using Joi 5.1.2 (API: https://github.com/hapijs/joi/blob/v5.1.0/README.md). Joi.array().includes() will be dropped in the next release in favour of Joi.array().items()


The object that you posted is not a valid JavaScript object because it's missing some closing } brackets. Here's the valid version:

var obj = {
  "workers" : [{
    "id" : "",   // <-------- Shouldn't be empty
    "wID" : {
      "idValue" : ""
    },
    "person" : {
      "governmentIDs":[{
        "itemID": "asd" 
      }],
      "legalName":{
        "givenName" : "PA",
        "middleName" : "",
        "preferredSalutations" : [{
          "salutationCode" : {
            "longName" : ""
          }
        }],
        "preferredName" : {
          "FormattedName" : ""
        },
      },
      "birthDate" : ""
    }
  }]
};

If I validate that with my provided schema, I get the following message (using Joi 5.1.0):

[1] workers at position 0 fails because id is not allowed to be empty