You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Ajv验证JSON Schema时遭遇MissingRefError问题求助

解决Ajv中引用定义时的MissingRefError问题

问题场景

我使用Ajv库验证数据,JSON Schema中定义了SetUserAccountDataPayload、UpdateUserAccountDataPayload、RemoveUserAccountDataPayload等多种类型,希望通过schema.definitions.SetUserAccountDataPayload的方式访问这些类型定义,但运行时出现错误。

错误信息

Uncaught MissingRefError: can't resolve reference #/definitions/UserAccountData from id #

当前代码

import Ajv from 'ajv';
import schema from 'app/features/cross-platform-bridge/types/cross-platform-bridge.types.json';

const ajv = new Ajv();

const validate1 = ajv.compile<SetUserAccountDataPayload>(schema.definitions.SetUserAccountDataPayload);
const validate2 = ajv.compile<UpdateUserAccountDataPayload>(schema.definitions.UpdateUserAccountDataPayload);
const validate3 = ajv.compile<RemoveUserAccountDataPayload>(schema.definitions.RemoveUserAccountDataPayload);

Schema内容

{
  "$ref": "#/definitions/SchemaRoot",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "AtLeastOne<UserAccountData>": {
      "anyOf": [
        {
          "additionalProperties": false,
          "properties": {
            "firstTimeDeposited": {
              "type": "boolean"
            },
            "kycState": {
              "$ref": "#/definitions/VerificationStatus"
            },
            "lastDepositedAt": {
              "type": "string"
            },
            "sessionStatus": {
              "$ref": "#/definitions/SessionStatus"
            },
            "userId": {
              "type": "string"
            }
          },
          "required": [
            "userId"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "properties": {
            "firstTimeDeposited": {
              "type": "boolean"
            },
            "kycState": {
              "$ref": "#/definitions/VerificationStatus"
            },
            "lastDepositedAt": {
              "type": "string"
            },
            "sessionStatus": {
              "$ref": "#/definitions/SessionStatus"
            },
            "userId": {
              "type": "string"
            }
          },
          "required": [
            "sessionStatus"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "properties": {
            "firstTimeDeposited": {
              "type": "boolean"
            },
            "kycState": {
              "$ref": "#/definitions/VerificationStatus"
            },
            "lastDepositedAt": {
              "type": "string"
            },
            "sessionStatus": {
              "$ref": "#/definitions/SessionStatus"
            },
            "userId": {
              "type": "string"
            }
          },
          "required": [
            "kycState"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "properties": {
            "firstTimeDeposited": {
              "type": "boolean"
            },
            "kycState": {
              "$ref": "#/definitions/VerificationStatus"
            },
            "lastDepositedAt": {
              "type": "string"
            },
            "sessionStatus": {
              "$ref": "#/definitions/SessionStatus"
            },
            "userId": {
              "type": "string"
            }
          },
          "required": [
            "firstTimeDeposited"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "properties": {
            "firstTimeDeposited": {
              "type": "boolean"
            },
            "kycState": {
              "$ref": "#/definitions/VerificationStatus"
            },
            "lastDepositedAt": {
              "type": "string"
            },
            "sessionStatus": {
              "$ref": "#/definitions/SessionStatus"
            },
            "userId": {
              "type": "string"
            }
          },
          "required": [
            "lastDepositedAt"
          ],
          "type": "object"
        }
      ]
    },
    "RemoveUserAccountDataPayload": {
      "additionalProperties": false,
      "properties": {
        "data": {
          "type": "null"
        },
        "type": {
          "type": "string"
        },
        "version": {
          "type": "string"
        }
      },
      "required": [
        "data",
        "type",
        "version"
      ],
      "type": "object"
    },
    "SchemaRoot": {
      "additionalProperties": false,
      "properties": {
        "removeUserAccountDataPayload": {
          "$ref": "#/definitions/RemoveUserAccountDataPayload"
        },
        "setUserAccountDataPayload": {
          "$ref": "#/definitions/SetUserAccountDataPayload"
        },
        "updateUserAccountDataPayload": {
          "$ref": "#/definitions/UpdateUserAccountDataPayload"
        }
      },
      "required": [
        "setUserAccountDataPayload",
        "updateUserAccountDataPayload",
        "removeUserAccountDataPayload"
      ],
      "type": "object"
    },
    "SessionStatus": {
      "enum": [
        "FAILED",
        "RESTRICTED",
        "SUCCESSFUL",
        "null"
      ],
      "type": "string"
    },
    "SetUserAccountDataPayload": {
      "additionalProperties": false,
      "properties": {
        "data": {
          "$ref": "#/definitions/UserAccountData"
        },
        "type": {
          "type": "string"
        },
        "version": {
          "type": "string"
        }
      },
      "required": [
        "data",
        "type",
        "version"
      ],
      "type": "object"
    },
    "UpdateUserAccountDataPayload": {
      "additionalProperties": false,
      "properties": {
        "data": {
          "$ref": "#/definitions/AtLeastOne<UserAccountData>"
        },
        "type": {
          "type": "string"
        },
        "version": {
          "type": "string"
        }
      },
      "required": [
        "data",
        "type",
        "version"
      ],
      "type": "object"
    },
    "UserAccountData": {
      "additionalProperties": false,
      "properties": {
        "firstTimeDeposited": {
          "type": "boolean"
        },
        "kycState": {
          "$ref": "#/definitions/VerificationStatus"
        },
        "lastDepositedAt": {
          "type": "string"
        },
        "sessionStatus": {
          "$ref": "#/definitions/SessionStatus"
        },
        "userId": {
          "type": "string"
        }
      },
      "required": [
        "userId",
        "sessionStatus",
        "kycState",
        "firstTimeDeposited",
        "lastDepositedAt"
      ],
      "type": "object"
    },
    "VerificationStatus": {
      "enum": [
        "EXPIRED",
        "PENDING",
        "TEMPORARY",
        "UNVERIFIED",
        "VERIFIED"
      ],
      "type": "string"
    }
  }
}

解决方案

错误原因是直接提取单个定义传给ajv.compile时,Ajv无法获取该定义内部引用的其他定义(比如SetUserAccountDataPayload依赖的UserAccountData),因为此时Ajv只拿到了单个定义的JSON,缺少整个Schema的上下文。

方式一:注册整个Schema后通过引用编译(推荐)

先将完整Schema注册到Ajv实例,再通过$ref引用具体定义编译验证函数:

import Ajv from 'ajv';
import schema from 'app/features/cross-platform-bridge/types/cross-platform-bridge.types.json';

const ajv = new Ajv();
// 注册整个Schema并指定标识
ajv.addSchema(schema, 'bridge-schema');

// 通过引用编译对应验证函数
const validate1 = ajv.compile<SetUserAccountDataPayload>({
  $ref: 'bridge-schema#/definitions/SetUserAccountDataPayload'
});
const validate2 = ajv.compile<UpdateUserAccountDataPayload>({
  $ref: 'bridge-schema#/definitions/UpdateUserAccountDataPayload'
});
const validate3 = ajv.compile<RemoveUserAccountDataPayload>({
  $ref: 'bridge-schema#/definitions/RemoveUserAccountDataPayload'
});

方式二:为单个定义补充依赖上下文

如果不想注册整个Schema,可以手动给单个定义添加definitions字段,包含它所有依赖的定义,适合依赖较少的场景:

import Ajv from 'ajv';
import schema from 'app/features/cross-platform-bridge/types/cross-platform-bridge.types.json';

const ajv = new Ajv();

// 为SetUserAccountDataPayload补充所有依赖的定义
const setPayloadSchema = {
  ...schema.definitions.SetUserAccountDataPayload,
  definitions: {
    UserAccountData: schema.definitions.UserAccountData,
    VerificationStatus: schema.definitions.VerificationStatus,
    SessionStatus: schema.definitions.SessionStatus
  }
};

const validate1 = ajv.compile<SetUserAccountDataPayload>(setPayloadSchema);

// UpdateUserAccountDataPayload需要额外添加AtLeastOne<UserAccountData>定义
const updatePayloadSchema = {
  ...schema.definitions.UpdateUserAccountDataPayload,
  definitions: {
    "AtLeastOne<UserAccountData>": schema.definitions["AtLeastOne<UserAccountData>"],
    UserAccountData: schema.definitions.UserAccountData,
    VerificationStatus: schema.definitions.VerificationStatus,
    SessionStatus: schema.definitions.SessionStatus
  }
};

const validate2 = ajv.compile<UpdateUserAccountDataPayload>(updatePayloadSchema);

内容的提问来源于stack exchange,提问作者AlexBor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 21:24:51