如何在没有循环依赖的模型之间正确共享Hapi-Joi验证模式

How to properly share Hapi Joi validation schemas between models without circular dependency

本文关键字:之间 共享 Hapi-Joi 模式 验证 模型 依赖 循环      更新时间:2023-09-26

我正在创建一个使用HAPI和Join验证输入的API,并且在不同模块之间共享验证模式时遇到了问题。我使用的是一个面向组件的体系结构,看起来像

components
|_ moduleA
   |_ moduleAController
   |_ moduleAModel
   |_ moduleARoute
   |_ moduleAValidate
|_ moduleB
   |_ moduleBController
   |_ moduleBModel
   |_ moduleBRoute
   |_ moduleBValidate
|_ moduleC
...

在每个模块中,moduleXRoute创建一个路由,将来自moduleXController的处理程序和来自moduleXValidate的验证器关联起来。

当我使用Joi时,我正在对输入数据进行一些测试,问题出在哪里,我的moduleA保留了moduleB的列表,而我的moduleB保留了对moduleA的引用,因此这意味着在验证器中:

var moduleASchema = {
    _id: Joi.objectId(),
    name: Joi.string().required(),
    moduleB: Joi.array().items(Joi.alternatives().try(Joi.objectId(), moduleBSchema)),
};
var moduleBSchema = {
        _id: Joi.objectId(),
        name: Joi.string().required(),
        moduleA: Joi.alternatives().try(Joi.objectId(), moduleASchema),
};

这就是为什么,我认为moduleAValidatemoduleBValidate公开其他模块可以使用的moduleASchemamoduleBSchema是一个好主意。

问题是它造成了一个循环依赖问题,因为在上面的情况下,我会有:

//moduleAValidate.js
var moduleBSchema = require('../moduleBValidate').moduleBschema;
//moduleBValidate.js
var moduleASchema = require('../moduleAValidate').moduleAschema;

因此,处理这个问题的好方法是什么?

我发现简单的方法是将所有模式集中在一个文件中,这可能是所有验证器所需要的,但我觉得这与组件体系结构相矛盾。

最好的方法是有一个中心点,将模式的公共部分保存在中心位置,并在需要时加载到所需的模式中。

我最终决定使用依赖注入来解决鸡和蛋的问题。在上面的例子中,我会做一些类似的事情

//moduleBValidate.js
var moduleBSchema = new (require('moduleBSchema.js'))();
var moduleASchema = new (require('moduleASchema.js'))(moduleBSchema); // Here I use dependency injection for injecting moduleBSchema in moduleASchema
//moduleAValidate.js
var moduleASchema = new (require('moduleASchema.js'))();
var moduleBSchema = new (require('moduleBSchema.js'))(moduleASchema);

我用这种方式构建了joi模式:

function moduleASchema(moduleBSchema, moduleCSchema...) { // Here we put all dependencies of moduleASChema
    moduleBSchema = moduleBSchema || Joi.object();
    moduleCSchema = moduleCSchema || Joi.object();
    ...
    this.schema = {
        name: Joi.string().required(),
        moduleBRef: Joi.alternatives().try(Joi.objectId(), moduleBSchema),
        moduleCRef: Joi.alternatives().try(Joi.objectId(), moduleCSchema)
    };
    return this.schema;
}
module.exports = SiteSchema;