tdegrunt / jsonschema

JSON Schema validation
Other
1.83k stars 263 forks source link

Annotations API #318

Open awwright opened 4 years ago

awwright commented 4 years ago

Provide a mechanism to collect annotations on instances. For example, "title" and "description". The result should be similar to a list of validation errors; including the schema & keyword setting the annotation, the instance, the property path to the instance, and the value of the annotation.

New options:

New ValidationResult properties:

Annotation has the following properties: keyword, value, instance

zoellner commented 3 years ago

would this enable the following use case:

I'd like to validate an object against a schema (created from an OpenAPI schema) but depending on the use case, ignore the required if the readOnly attribute is set. E.g. an API payload to create an object would not require the id in the example below since that is added later by the database.

Payload

{"name": "Test"}

Schema

{
  "type": "object",
  "required": [
    "id",
    "name"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "Unique ID for the resource",
      "readOnly": true
    },
    "name": {
      "type": "string",
      "description": "Name of the resource"
    }
  }
}

I'd like to validate this and have it pass by setting an option to ignore the required for the property that has the readOnly attribute set.

and bonus question: Is there a way to accomplish this before this is implemented?

zoellner commented 2 years ago

Came across this again. In case anyone else is looking into this. My workaround for now is as follows:

  1. Use preValidateProperty function to modify the required array

    function preValidateProperty(object, key, schema) {
    // make readOnly properties not required
    if (schema.type === 'object' && schema.required) {
    const readOnlyProperties = Object.entries(schema.properties)
      .filter(([, v]) => v.readOnly)
      .map(([k]) => k);
    
    schema.required = schema.required.filter(property => !readOnlyProperties.includes(property));
    }
    }
  2. Wrap schema and data since preValidateProperty is not called for the toplevel schema

    
    const { Validator } = require('jsonschema');
    const jsonValidator = new Validator();

const validatorOptions = { preValidateProperty // see code snippet above };

function validateSomething(data, schema) { let wrappedSchema = schema; let wrappedData = data; if (schema.type === 'object' && schema.required) { wrappedSchema = { data: { schema } }; wrappedData = { data }; }

const { errors, valid } = jsonValidator.validate(wrappedData, wrappedSchema, validatorOptions); return {errors, valid}; }