使用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
相关产品推荐
相关产品推荐

