Joi: JSON object/string validation

Created on 19 Sep 2019  路  7Comments  路  Source: sideway/joi

Context

  • node version: 8+
  • joi version: 16.1.1
  • environment (node, browser): Node
  • used with (hapi, standalone, ...): Standalone
  • any other relevant information: Screenshot

What are you trying to achieve or the steps to reproduce ?

How to validate an object that's a JSON string? The code below below produces an error. IIRC, the old-style Joi.validate(json string, schema) automatically converts JSON string to object.

const schema = Joi.object({
  foo: Joi.object().required()
});

console.log(schema.validate({ foo: '{"one": 1}' }));

Which result you had ?

{ value: { foo: '{"one": 1}' },
  error:
   { ValidationError: "foo" must be of type object _original: { foo: '{"one": 1}' }, details: [ [Object] ] } }

What did you expect ?

Automatic String to JSON conversion that passes validation.

Screenshot of v16.1.1 doc :https://hapi.dev/family/joi/?v=16.1.1#object
screenshot

documentation

Most helpful comment

The release notes example given above does not match the example given in the current docs https://hapi.dev/family/joi/?v=16.1.7#extensions. Is the coerce function meant to take params coerce(value, helpers) or coerce(value, schema)? These appear to do different things.

I had to fix this recently and this was my working code for object coercion only. Note that the convert defaults to true so you don't have to set this explicity.

const custom = Joi.extend((joi) => {

  return {
    type: 'object',
    base: joi.object(),
    coerce(value, schema) {

      if (value[0] !== '{' &&
        !/^\s*\{/.test(value)) {
        return;
      }

      try {
        return { value: JSON.parse(value) };
      }
      catch (err) {
        console.log(err);
      }
    }
  };
});
...
# in route options use `custom` joi instance
validate: {
  payload: custom.object({
      version: Joi.string().optional(),
      name: Joi.string().lowercase()
    }).unknown()
  }
... # set a failAction to debug?
}

All 7 comments

Read the release notes. It is described in details with examples on how to do it yourself.

https://github.com/hapijs/joi/issues/2037 doesn't seem to mention this change. Could you provide the reference on how this should be done now?

Search for Array and object string coercion

For others who might not be aware of this during upgrade in the future
From https://github.com/hapijs/joi/issues/2037
screenshot

I had problems with the documented solution in #2037 .
The coerce.method shoud must be defined as method(value, scehma) otherwise it won't work. ( #2152 )

The release notes example given above does not match the example given in the current docs https://hapi.dev/family/joi/?v=16.1.7#extensions. Is the coerce function meant to take params coerce(value, helpers) or coerce(value, schema)? These appear to do different things.

I had to fix this recently and this was my working code for object coercion only. Note that the convert defaults to true so you don't have to set this explicity.

const custom = Joi.extend((joi) => {

  return {
    type: 'object',
    base: joi.object(),
    coerce(value, schema) {

      if (value[0] !== '{' &&
        !/^\s*\{/.test(value)) {
        return;
      }

      try {
        return { value: JSON.parse(value) };
      }
      catch (err) {
        console.log(err);
      }
    }
  };
});
...
# in route options use `custom` joi instance
validate: {
  payload: custom.object({
      version: Joi.string().optional(),
      name: Joi.string().lowercase()
    }).unknown()
  }
... # set a failAction to debug?
}

I guess I missed this thread. I want to either accept on a hapi route either a text message to be passed through a socket to inform someone of a change in state of a database OR I want to pass a json object with unknown specifics that describe the change in data that needs to be updated by the front end. How do I define a generic json object with hapi joi? Just a string or just an object?

Was this page helpful?
0 / 5 - 0 ratings