You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Ajv如何在自定义关键字中使用$data引用?

Handling $data References in Ajv Custom Keywords

Great question! I’ve faced this exact issue with Ajv custom keywords before—since Ajv only natively supports $data for its built-in keywords, you do need to handle the resolution manually in your custom keyword’s validation logic. Your initial idea of using the validation function’s parameters to extract the referenced value is totally valid, and there’s a clean, reliable way to implement it using Ajv’s built-in utilities.

Here’s a step-by-step solution:

  1. Ensure $data is enabled in your Ajv instance
    First, you must initialize Ajv with the $data option set to true—this enables the internal utilities needed to resolve $data references.

  2. Modify your custom range keyword to resolve $data references
    In your keyword’s validation function, check if the schema is a $data reference. If it is, use Ajv’s resolveData method to fetch the actual range configuration from the target field. Then proceed with your standard range validation logic.

Example Code:

const Ajv = require("ajv");
const ajv = new Ajv({ $data: true }); // Critical: Enable $data support

ajv.addKeyword({
  keyword: "range",
  type: "number",
  schemaType: "any", // Allow both direct range objects and $data references
  validate: function (schema, data, _, __, ___, ____, rootData) {
    // Resolve $data reference if present
    let rangeConfig = schema;
    if (schema.$data) {
      // Use Ajv's built-in resolveData to handle path resolution
      rangeConfig = ajv.resolveData(rootData, schema.$data);
      
      // Handle cases where the referenced field doesn't exist
      if (rangeConfig === undefined) {
        return false; // Adjust this behavior based on your requirements
      }
      
      // Optional: Validate the resolved config matches expected structure
      if (typeof rangeConfig !== "object" || rangeConfig === null) {
        return false;
      }
    }

    // Run your original range validation logic
    const { min, max } = rangeConfig;
    if (min !== undefined && data < min) return false;
    if (max !== undefined && data > max) return false;
    return true;
  },
  errors: true,
  messages: {
    range: "Value must be between {{schema.min}} and {{schema.max}}"
  }
});

How to Use This:

Define your schema with a $data reference for the range keyword, and validate your data as usual:

// Sample data
const inputData = {
  allowedRange: { min: 10, max: 20 },
  measurement: 15
};

// Schema with $data reference
const validationSchema = {
  type: "object",
  properties: {
    allowedRange: {
      type: "object",
      properties: {
        min: { type: "number" },
        max: { type: "number" }
      },
      required: ["min", "max"]
    },
    measurement: {
      type: "number",
      range: { $data: "1/allowedRange" } // Reference parent's allowedRange field
    }
  }
};

// Validate
const validate = ajv.compile(validationSchema);
const isValid = validate(inputData);

console.log(isValid); // true
console.log(validate.errors); // null (no errors)

Key Notes:

  • Use resolveData instead of manual path parsing: Ajv’s resolveData handles all the edge cases of $data path syntax (like 0/ for current level, 1/ for parent level, nested paths, etc.) so you don’t have to reinvent the wheel.
  • Handle missing references: Decide how you want to handle cases where the referenced field doesn’t exist (return false, default to an open range, etc.) based on your use case.
  • Validate resolved config structure: Adding a check that the resolved rangeConfig is an object ensures your validation logic doesn’t fail unexpectedly if the referenced field has the wrong type.

Your initial approach to leverage the validation function’s parameters was on the right track—this solution just formalizes it using Ajv’s built-in tools to ensure robustness.

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

火山引擎 最新活动