kenspirit/joi-to-json

object.pattern(pattern, schema, [options]) not handled correctly

Closed this issue · 11 comments

Hello!
object.pattern(pattern, schema, [options]) not handled correctly
doc joi https://joi.dev/api/?v=17.6.0#objectpatternpattern-schema-options

const schema = Joi.object().pattern(Joi.string().min(2).max(5), Joi.string());

should return something like that:
additionalProperties:{ type: 'string', style: 'form', explode: true, },

but it returns this result:
` properties: {
undefined: {
type: 'string',
....

additionalProperties: false
`

Hi @PashaGeronimo,

Originally, dynamic object key support is raised through this issue and supported by its corresponding PR.

The support is quite limited because JSON schema does not seem to have this kind of dynamic validation.

Your example additionalProperties:{ type: 'string', style: 'form', explode: true, } is the JSON to be validated against, but not the JSON schema to be used for validation.

What should be the converted json schema looks like for the defined joi schema and how should it be used?

I probably don't fully understand you. I can tell you more. I use the fastify-swagger-joi bundle
In Joi I describe validation:
price_free:Joi.object().pattern(Joi.string().min(2).max(5), Joi.object().keys({ quantity:Joi.string(), descr:Joi.string(), id:Joi.string(), })),
The result is not what I expected. So dynamic fields don't work in this case.
I assumed that the output should be such a result:
price_free: { type: 'object', additionalProperties: { type: 'object', style: 'form', explode: true, properties: { quantity: { type: 'string' }, descr: { type: 'string' }, id: { type: 'string' }, }, additionalProperties:false } } },
It turns out that I can't use Joi and your converter to handle dynamic keys
Thanks

Hi @PashaGeronimo,

I don't think your expected output can be generated like that. Where does the "style" and "form" field come from?

I check the JSON schema and dynamic field validation should be some regex validating the key and defined in JSON schema like this documentation

I am thinking the output might look like this:

{
  price_free: {
    type: 'object',
    patternProperties: {
        "^[a-zA-Z]{2,5}$": {
            type: 'object',
            properties: { quantity: { type: 'string' }, descr: { type: 'string' }, id: { type: 'string' } }
        }
    }
  }
}

Please first define a valid JSON schema and try to validate your JSON in fastify. Then we can see how it can be defined in Joi and how to use joi-to-json converts it.

What is more, I checked Swagger Specification. It seems Swagger does not support patternProperties as well. You may need to check if fastify-swagger can properly work on dynamic key validation before really adopting this approach.

Verison 2.2.2 is released and has adopted the patternProperties approach. You can change your pattern parameter to a regular expression to see if fastify-swagger works or not. At least for now, there will be no undefined issue as you met.

Added the known limitation about this object.pattern usage to readme as well unless I can convert the Joi schema to regular expression later.

Your update made a difference, thanks.
The update helped
This JOI code
price_free:Joi.object().pattern(/\w\d/, Joi.object({ descr:Joi.string(), })),

this code creates such json:
price_free: { type: 'object', properties: { '/\\w\\d/': { type: 'object', properties: { descr: { type: 'string' } }, required: [] } },
But there is one problem, nested keys in a dynamic key are not filtered
except for the field "descr" pass any other fields
this solution helps (added additionalProperties:false after second required: [],):
price_free: { type: 'object', properties: { '/\\w\\d/': { type: 'object', properties: { descr: { type: [ 'string', 'null' ] } }, required: [] } }, additionalProperties: false, patternProperties: { '\\w\\d': { type: 'object', properties: { descr: { type: [ 'string', 'null' ] } }, required: [], additionalProperties:false } } },
How can I change the code in Joi to make this line appear additionalProperties:false?

Thanks!

image
Screenshot explains better.

Hi @PashaGeronimo,

joi allowUnknown options can be used. You can set it globally or particularly on any nested level. You can find some usage in the fixture folder or check the Joi documentation.

I tried to do according to the documentation.

const Joi = require('joi').defaults((schema) => schema.options({
allowUnknown: false
}));

But this changes all true/false values ​​but is not added to patternProperties

patternProperties does not contain a additionalProperties key

Hi,

The unknown flag is a bit tricky when dealing with the pattern. Just fix it in release 2.2.3.

And you can also append .unknown(false) to your joi object instead of using the verbose joi default definition.

2.2.3. - now all worked! Thank you very much!

Wlc