Home > database >  NjsonSchema Validation If Property1 is equal to Something then require Property2
NjsonSchema Validation If Property1 is equal to Something then require Property2

Time:02-14

I seem to not be able to get const or enum working as part of an if-then-else JSON schema validation.

They seem to be interchangeable when 1 validation value is concerned. (Reference)

Here is my JSON schema

    {
      "$schema": "http://json-schema.org/draft-07/schema#",
      "title": "Test_Schema",
      "description": "A schema for validating a test object",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "GeneralData": {
          "type": "object",
          "description": "Advsor and admin customer information",
          "properties": {
            "Name": {
              "type": [ "string", "null" ],
              "description": "Customer's advisor name"
            },
            "Age": {
              "type": [ "string", "null" ],
              "description": "Customer's advisor email"
            },
            "Location": {
              "type": [ "string", "null" ],
              "description": "The advisor's manager email'"
            }
          },
          "required": [ "Name", "Location", "Age" ]
        },
        "ClientData": {
          "type": "object",
          "description": "Customer's information",
          "additionalProperties": false,
          "properties": {
            "Title": {
              "type": [ "string", "null" ]
            },
            "Forename": {
              "type": [ "string", "null" ]
            },
            "Surname": {
              "type": [ "string" ]
            }
          },
          "required": [ "Title" ],
          "if": {
            "properties": {
              "Forename": { "enum": [ "Soameonea" ] }
            },
            "required": [ "Forename" ]
          },
          "then": { "required": [ "Surname" ] },
          "else": false 
        }
      }
    }

If Forename = "Someone" I want Surname to be required.

Here is my jsonObject after serialization:

     {
        "GeneralData": {
            "Name": "Not Relevant",
            "Age": "Not Relevant",
            "Location": "Not Relevant"
        },
        "ClientData": {
            "Title": "SomeTitle",
            "Forename": "Someone",
            "Surname": null
        }
    }

Validation code:

     internal void ValidateDataObjectOnSchema()
            {
                var dataObject = PopulateDataObject();
                var json = JsonConvert.SerializeObject(dataObject);
                var result = GetSchema().Validate(json);
                var errors = result.Select(x =>
                {
                    return new Errors() { Title = x.Property, Description = x.Schema.Description };
                });
                var i = errors;
    
            }

      internal JsonSchema GetSchema()
            {
                return JsonSchema.FromFileAsync("Test/testSchema.json").Result;
            }

Right now it still requires Surname, even though the enum Soameonea != Someone and I only require Title. <== Issue1

In the JSON schema if I set "Surname":{"type":["string","null]} then the error disappears and still I don't get the error if I then change the if condition for the Forename enum to "Someone". <== Issue 2

I cannot get a different validation output if I replace Enum with Const, So if I can get one to work I'm sure the other will follow.

I've found several answers to this question (Answer 1), I try to implement the same thing and for some reason, it fails in my case.

What am I missing?

CodePudding user response:

The same code and json work with the package Newtonsoft.Json.Schema (Reference)

Code:

  internal void ValidateDataObjectOnSchemaWithNewtonSoftJson()
        {
            var dataObject = PopulateDataObject();
            var settings = new JsonSerializerSettings()
            {
                NullValueHandling = NullValueHandling.Ignore

            };
            var jsonDataObjectString = JsonConvert.SerializeObject(dataObject, settings);
            JObject jsonDataObject = JObject.Parse(jsonDataObjectString);
            var jsonSchemaFile = File.ReadAllText("Test/testSchema.json");
            var schema = JSchema.Parse(jsonSchemaFile);
            ;
            IList<ValidationError> messages;
            var result = jsonDataObject.IsValid(schema, out messages);
            var errors = GetReadableResult(result, messages);

        }

        private List<Errors> GetReadableResult(bool result, IList<ValidationError> messages)
        {
            var errors = new List<Errors>();

            if (!result)
            {
                foreach (var error in messages)
                {
                    if (error.ChildErrors.Count > 0)
                    {
                        errors.Add(
                            new Errors()
                            {
                                Path = error.ChildErrors.FirstOrDefault()?.Path,
                                Kind = error.ChildErrors.FirstOrDefault()?.Message
                            });
                    }
                    else
                    {
                        errors.Add(new Errors()
                        {
                            Path = error.Path,
                            Kind = error.Message
                        });
                    }
                }
            }

            return errors;
        }

JsonSchema:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Test_Schema",
  "description": "A schema for validating a test object",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "GeneralData": {
      "type": "object",
      "description": "Advsor and admin customer information",
      "properties": {
        "Name": {
          "type": [ "string", "null" ],
          "description": "Customer's advisor name"
        },
        "Age": {
          "type": [ "string", "null" ],
          "description": "Customer's advisor email"
        },
        "Location": {
          "type": [ "string", "null" ],
          "description": "The advisor's manager email'"
        }
      },
      "required": [ "Name", "Location", "Age" ]
    },
    "ClientData": {
      "type": "object",
      "description": "Customer's information",
      "additionalProperties": false,
      "properties": {
        "Title": {
          "type": [ "string", "null" ]
        },
        "Forename": {
          "type": "string"
        },
        "Surname": {
          "type": [ "string" ]
        }
      },
      "required": [ "Title" ],
      "if": {
        "properties": {
          "Forename": { "enum": [ "Someone" ] }
        },
        "required": [ "Forename" ]
      },
      "then": { "required": [ "Surname" ] },
      "else": {}
    }
  }
}

The only addition would be to make the GetReadableResult recursive for Errors which have multiple child items.

CodePudding user response:

In the JSON schema if I set "Surname":{"type":["string","null]} then the error disappears

A property with a null value still has a value. If you want to say that the property value must not only exist, but not be null, then add "type": "string" to your then condition.

  • Related