hapi
hapi copied to clipboard
Remove Joi from types
This PR removes the explicit import of Joi
in the typings. As it is, any typescript users that use Hapi, will need to add a dependency of Joi, just to resolve the typings.
The explicit dependency is replaced by a generic validator that can be set on the Server
object, or inferred from the config. This has the additional advantage, that other validators will be able to be typed instead of assuming that Joi is used.
The new types will require a bit of work to adapt to for projects that use server.validate()
.
This fixes #4491.
Definition
const MySimpleValidator = {
compile(schema: MySchema) {
return {
validate(value: unknown, options: MyOptions & { context?: Validation.Context }) {
return { value: 'everything is awesome' };
}
};
}
};
The base Joi object already implement this interface.
Registration
Explicit:
const server = new Server<ServerApplicationState, typeof Joi>({});
server.validator(Joi);
Inferred from config:
const server = new Server({
routes: { validate: { validator: Joi } }
});
Using the new validator()
returned value:
const server = new Server({})
.validator(Joi);
For plugins
Explicit:
register(server: Server<unknown, typeof Joi>, options: any) {
server.validator(Joi);
…
}
Using the new validator()
returned value:
register(_server: Server, options: any) {
const server = _server.validator(Joi);
…
}
Usage
Once registered, the validator typings are used to help type the validation options:
server.route({
…,
options: {
validate: {
options: {
// Validated against the options that can be passed to the registered `validate()` method
},
query: {
// Validated against the type of the `schema´ from the registered `compile()` method
}
}
}
});
It can be overriden at the route level:
server.route({
…,
options: {
validate: {
validator: Joi, // Route-only validator
options: {
// Validated against the options that can be passed to the validator `validate()` method
},
query: {
// Validated against the type of the `schema´ from the validator `compile()` method
}
}
}
});
It also allows custom inline validators:
server.route({
…,
options: {
validate: {
query: (value, optionsAndContext) {
// optionsAndContext is typed with the `context` object
}
}
}
});
It is also used to validate rules:
server.rules(processor, {
validate: {
schema: validateSchema, // Validated against the type of the `schema´ from the registered `compile()` method
options: {
// Validated against the options that can be passed to the registered `validate()` method
}
}
});
As it currently is, pre-compiled Joi schemas continue to work, even with no registered validator (though any options won't be validated):
server.route({
…,
options: {
validate: {
query: Joi.object({
…
})
}
}
});
FYI, it's possible that this could be revised to extract the allowed options from the passed Joi object.