lightsofapollo / joi-to-json-schema

140 stars 39 forks source link

what's the trick to excluding default functions? #5

Open WebServiceTeam opened 9 years ago

WebServiceTeam commented 9 years ago

If I have a joi schema like this:

joi.object().keys({ foo: joi.string().default('foo'), bar: joi.string().default('bar'), created: joi.date().default(Date.now, 'generated'), updated: joi.date().default(Date.now, 'generated') })

And I don't want the function defaults to come through into the json schema export, but I do want the static defaults, how do I achieve that?

By just calling convert(schema) by default I get this:

{ type: 'object', properties: { foo: { default: 'foo', type: 'string' }, bar: { default: 'bar', type: 'string' }, created: { default: [Object], type: 'string', format: 'date-time' }, updated: { default: [Object], type: 'string', format: 'date-time' }, }, additionalProperties: false }

That [Object] is the Date.now function

raisch commented 9 years ago

If you pass a function as the default to a Joi schema, you'll see it in the JSON Schema. What value would you expect to see? The problem here is that the schema does have a default so returning null or no default in the JSON Schema would not be representative of the original. As a solution, you might consider post-processing the result of the conversion to remove (or otherwise manipulate) any instance of /default:\s\[Object\],?/

WebServiceTeam commented 9 years ago

The problem is you just get the string representation of the function, which can break validation for types. In the case above, the literal value Date.now fails the date-time format validation.

I would expect that if the default in joi was set to a function (and not the output of a function invocation, which should pass through post-evaluation), default would just be omitted from the JSON schema conversion since the string representation of the function is meaningless.

raisch commented 9 years ago

Hmm..but as I wrote above, that would indicate that the value had no default, which is not true.

WebServiceTeam commented 9 years ago

Yes, but setting the default to a function in Joi is a special Joi-specific instruction to use the function as a generator, and JSON schema has no concept of generators. Maybe it could be interpreted as required?

raisch commented 9 years ago

You could also provide a transformer as the second argument to the convert() function to convert unacceptable values to whatever you'd like.

ghost commented 9 years ago

Sorry, I logged this issue from my shared company Github account instead of my personal. I just think that since your module is providing a translation from Javascript to JSON, it shouldn't try to convert types that aren't valid in JSON, functions inclusive. If I try to JSON.stringify() a function, it comes back undefined.

raisch commented 9 years ago

Here's a start for writing your own transformer:

var util=require('util'),
    joi=require('joi'), 
    convert=require('joi-to-json-schema');

var s=joi.object({
    created: joi.date().default(Date.now,'date for now')
});

console.log(convert(s,function(elt){
  console.log('elt:'+util.inspect(arguments,{depth:null}));
  return elt;
}));
raisch commented 9 years ago

And I do understand your point. I'll mark this as a bug and see what I can do.