joi
joi copied to clipboard
Wrapping of nested schema properties
Support plan
- is this issue currently blocking your project? (yes/no): no
- is this issue affecting a production system? (yes/no): no
Context
- node version: n.a
-
module version:
17.4.0
- environment (e.g. node, browser, native): node
- used with (e.g. hapi application, another framework, standalone, ...): hapi
- any other relevant information:
How can we help?
Let's say I am using a library that performs Joi Schema validation:
const configSchema = Joi.object().keys({
foo: Joi.object().keys({
bar: Joi.number().min(0)
})
})
Now let's pretend that I want to be able to write a "dynamic" (interpreted) configuration using environement variables:
const config = {
foo: {
bar: "{ env.FOO_BAR }"
}
}
How should I write a "schema transform" function that will transform the initial configSchema
into something like:
const configSchemaWithEnv = Joi.object().keys({
foo: Joi.object().keys({
bar: Joi.alternatives(
Joi.number().min(0), // Initial value
Joi.string().regexp(ENV_VAR_REXEXP)
)
})
})
(of course any input would need to be interpreted before being actually used, but that's not the point)
In other words, how can I write a addEnvVarSupportToJoiSchema
that transforms a basic schema by wrapping every/some parts of it ?
const addEnvVarSupportToJoiSchema = (schema) => {
//
return alteredSchema
}
const configSchemaWithEnv = addEnvVarSupportToJoiSchema(configSchema)
Alternatively, if needed, I could also use something that allows passing a custom Joi object:
const configSchemaCreator = (joi) => joi.object().keys({
foo: joi.object().keys({
bar: joi.number().min(0)
})
})
const alteredSchema = addEnvVarSupportToJoiSchemaUsingCustomJoi(configSchemaCreator)
Could you point me how to do this.
My current workaround requires me to write schemas in a quite ugly way:
const withCustomWrapper = (fn) => {
const joi = Joi.extend(withEnvString)
// and more
return fn(joi, (s) => joi.alternaties().try(s, joi.envString()))
}
const createSchema = (joi = Joi, propWrapper = x => x) => {
return joi.object().keys({
foo: joi.object().keys({
bar: propWrapper(joi.number())
})
})
}
const schemaWithoutEnvSupport = createSchema()
const schemaWithEnvSupport = withCustomWrapper(createSchema)
Which is quite fine from a usability point of view but I'd like a better separation of concerns when writing the schema (avoid having to "know" that properties might need to be wrapped).
I personally don't see a proper way to do this, an alternative to what you're doing could be describe
-> alter -> compile
but that feels weird. Or add some kind of api to concat
to allow overrides under specific conditions.
For the record npm did a joi extension to deal with environment but that probably won't help you.
Thanks for your answer. My actual use case isn't really related to env variables, this was more of an example on what I was trying to achieve.
I did fear this wouldn't be possible out of the box. But since I have the ability to have full control over the joi
instance used, would it be possible to "sub instance" (sub-class the live instance) to achieve my goal? If so, how would I do that? Where should I look (in addition to the concat
method you already mentioned)
I'll also look into the describe/compile which I didn't think about, thanks.
I'm not exactly sure what you're trying to achieve but wouldn't extensions work for your case ?