【问题标题】:Using when/alternatives inside when在when中使用when/alternatives
【发布时间】:2019-10-08 14:57:45
【问题描述】:

我需要使用joi 验证架构。

对象是这样的:

  1. 有一个名为“type”的必需属性,其值可以是TYPE1TYPE2TYPE3
  2. 如果type === 'TYPE1',我们必须期望属性onetwothree在同一级别。
  3. 如果type === 'TYPE2',我们必须期望属性fourfivesix处于同一级别。
  4. 如果type === 'TYPE3',我们必须期望subtype 属性在同一级别,可能的值AB
    • 如果subtype === 'A',那么我们必须期望属性seveneightnine处于同一级别。
    • 如果subtype === 'B',那么我们必须期望属性teneleventwelve处于同一级别。

这是我想出的:

import { object, string, validate } from 'joi';

const obj1 = { // valid
  type: 'TYPE1',
  one: '01',
  two: '02',
  three: '03',
};
const obj2 = { // valid
  type: 'TYPE2',
  four: '04',
  five: '05',
  six: '06',
};
const obj3 = { // valid
  type: 'TYPE3',
  subtype: 'A',
  seven: '07',
  eight: '08',
  nine: '09',
};
const obj4 = { // valid
  type: 'TYPE3',
  subtype: 'B',
  ten: '10',
  eleven: '11',
  twelve: '12',
};

const joiSchema = object({
  // point 1
  type: string().valid('TYPE1', 'TYPE2', 'TYPE3').required(),
})
.when(
  // point 2
  object({ type: 'TYPE1' }).unknown(),
  {
    then: object({
      one: string().required(),
      two: string().required(),
      three: string().required(),
    }),
  },
)
.when(
  // point 3
  object({ type: 'TYPE2' }).unknown(),
  {
    then: object({
      four: string().required(),
      five: string().required(),
      six: string().required(),
    }),
  },
)
.when(
  // point 4
  object({ type: 'TYPE3' }).unknown(),
  {
    then: object(
      // if type === 'TYPE3', check for one of those schemas
      {
        // point 4
        subtype: string().valid('A', 'B'),
      },
    ).when(
      // point 4.1
      object({ subtype: 'A' }).unknown(),
      {
        then: object({
          seven: string().required(),
          eight: string().required(),
          nine: string().required(),
        }),
      },
    ).when(
      // point 4.2
      object({ subtype: 'B' }).unknown(),
      {
        then: object({
          ten: string().required(),
          eleven: string().required(),
          twelve: string().required(),
        }),
      },
    ),
  },
);

const result1 = validate(obj1, joiSchema);
console.log('Validating obj1')
if (result1.error) {
  console.error(result1.error.message);
}

const result2 = validate(obj2, joiSchema);
console.log('Validating obj2')
if (result2.error) {
  console.error(result2.error.message);
}

const result3 = validate(obj3, joiSchema);
console.log('Validating obj3')
if (result3.error) {
  console.error(result3.error.message);
}

const result4 = validate(obj4, joiSchema);
console.log('Validating obj4')
if (result4.error) {
  console.error(result4.error.message);
}

此 sn-p 可在此处进行测试:https://repl.it/@AlessandroDe5/Joi-MCVE

显示这个错误:

AssertionError [ERR_ASSERTION]: Cannot merge type object with another type: alternatives
    at new AssertionError (internal/errors.js:315:11)
    at Object.exports.assert (/home/runner/node_modules/hoek/lib/index.js:559:11)
    at internals.Object.concat (/home/runner/node_modules/joi/lib/types/any/index.js:148:14)
    at internals.Alternatives.when (/home/runner/node_modules/joi/lib/types/alternatives/index.js:131:52)
    at index.ts:52:6
    at Script.runInThisContext (vm.js:65:33)
    at startRepl (/usr/local/lib/node_modules/ts-node-fm/src/bin.ts:157:12)
    at Object.<anonymous> (/usr/local/lib/node_modules/ts-node-fm/src/bin.ts:66:1)
    at Module._compile (internal/modules/cjs/loader.js:654:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:665:10)

如果我删除嵌套的 when(第 4、4.1、4.2 点),它可以正常工作,并且当然会拒绝最后两个对象。

我还尝试将when 替换为alternatives

.when(
  // point 4
  object({ type: 'TYPE3' }).unknown(),
  {
    then: alternatives().try(
      object({
        subtype: string().valid('A'),
        seven: string().required(),
        eight: string().required(),
        nine: string().required(),
      }),
    ).when(
      object({
        subtype: string().valid('B'),
        ten: string().required(),
        eleven: string().required(),
        twelve: string().required(),
      }),
    ),
  },
);

正如人们所料,我得到了完全相同的错误。

有没有办法以某种方式完成任务?

【问题讨论】:

  • 你检查过这个 github 问题了吗? github.com/hapijs/joi/issues/1021 听起来和你的问题很相似。不过,在第 52 行抛出了错误,这很奇怪。
  • @briosheje 是的,我看过那个问题,不幸的是他们说要使用when/is/then/otherwise,这是有限制的,因为我只能有两个分支(thenotherwise)。我的 MCVE 被简化了,我的真实场景是大约 10 种不同的模式,它们基于 subtype 而不同,所以我不能在这里使用这个解决方案。也许我可以链接when/otherwise 来重现if/else if 场景,但这看起来很难看。这是唯一的解决方案吗?
  • 不确定,我个人以前从未使用过 joi。也许其他人有其他想法。否则,您可能想打开另一个问题或重新打开现有问题,也许作者或团队可能会给您进一步的帮助

标签: javascript typescript joi


【解决方案1】:

我建议使用 Joi.alternatives() 的不同方法,这样您可以避免嵌套 when,因此您的架构应该如下所示:

Joi.alternatives().try(
    Joi.object({
        type: Joi.string().valid('TYPE1').required(),
        one: Joi.string().required(),
        two: Joi.string().required(),
        three: Joi.string().required(),
    }),
    Joi.object({
        type: Joi.string().valid('TYPE2').required(),
        four: Joi.string().required(),
        five: Joi.string().required(),
        six: Joi.string().required(),
    }),
    Joi.object({
        type: Joi.string().valid('TYPE3').required(),
        subtype: Joi.string().valid('A', 'B')
    })
        .when(Joi.object({ subtype: 'A' }).unknown(), {
            then: Joi.object({
                seven: Joi.string().required(),
                eight: Joi.string().required(),
                nine: Joi.string().required(),
            }),
        })
        .when(Joi.object({ subtype: 'B' }).unknown(), {
            then: Joi.object({
                ten: Joi.string().required(),
                eleven: Joi.string().required(),
                twelve: Joi.string().required(),
            }),
        }),
);

【讨论】:

  • 不幸的是,正如 cmets 中所说,我的属性和可能的​​值比问题中显示的要多(我做了一个简短的例子来演示这个问题,我的真实场景更大),所以这会导致在很多不必要的重复中。我最终放弃了 joi 或 ajv,它支持针对 JSON-Schema 草案 07 的验证(它支持嵌套的 when 子句并且比 Joi 的 js 模式更具可读性)。非常感谢!
  • 没问题!但是,是的,我同意,Joi 可能不是复杂模式的正确选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-31
  • 2012-05-27
  • 1970-01-01
  • 2019-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多