24

Is there a way to validate a JSON structure against a JSON schema for that structure? I have looked and found JSON.Net validate but this does not do what I want.

JSON.net does:

JsonSchema schema = JsonSchema.Parse(@"{
  'type': 'object',
  'properties': {
    'name': {'type':'string'},
    'hobbies': {'type': 'array'}
  }
}");

JObject person = JObject.Parse(@"{
  'name': 'James',
  'hobbies': ['.NET', 'LOLCATS']
}");

bool valid = person.IsValid(schema);
// true

This validates to true.

JsonSchema schema = JsonSchema.Parse(@"{
  'type': 'object',
  'properties': {
    'name': {'type':'string'},
    'hobbies': {'type': 'array'}
  }
}");

JObject person = JObject.Parse(@"{
  'surname': 2,
  'hobbies': ['.NET', 'LOLCATS']
}");

bool valid = person.IsValid(schema);

This also validates to true

JsonSchema schema = JsonSchema.Parse(@"{
  'type': 'object',
  'properties': {
    'name': {'type':'string'},
    'hobbies': {'type': 'array'}
  }
}");

JObject person = JObject.Parse(@"{
  'name': 2,
  'hobbies': ['.NET', 'LOLCATS']
}");

bool valid = person.IsValid(schema);

Only this validates to false.

Ideally I would like it to Validate that there are no fields aka name in there that shouldn't be in there aka surname.

Liam
  • 27,717
  • 28
  • 128
  • 190
Shaun Groenewald
  • 866
  • 1
  • 17
  • 34
  • do you want to validate string(schema) vs. string(given object) or could you use an object as schema? – Liran Oct 23 '13 at 14:19
  • yes, something like SCHEMA `...{'Name' : string , 'Cars': int ....}` vs OBJ `...{'Name' : Bob, 'Pants': 2....}` is false but `...{'Name' : Bob, ....}` is true. I would get in a JSON string and I would need to compare it to the schema in the db to make sure it is valid. – Shaun Groenewald Oct 23 '13 at 14:22
  • again ill try to ask more clear, can it be that the schema be a C# object that you have and u want to test it against incoming unknown strings? – Liran Oct 23 '13 at 14:29
  • I am not sure if I understand you correctly but here goes: I get in a unknown string and I want to compare it to a schema string that I have. That sounds like its about what you are asking. – Shaun Groenewald Oct 23 '13 at 14:37

4 Answers4

19

I think that you just need to add

'additionalProperties': false

to your schema. This will stop unknown properties being provided.

So now your results will be:- True, False, False

test code....

void Main()
{
var schema = JsonSchema.Parse(
@"{
    'type': 'object',
    'properties': {
        'name': {'type':'string'},
        'hobbies': {'type': 'array'}
    },
    'additionalProperties': false
    }");

IsValid(JObject.Parse(
@"{
    'name': 'James',
    'hobbies': ['.NET', 'LOLCATS']
  }"), 
schema).Dump();

IsValid(JObject.Parse(
@"{
    'surname': 2,
    'hobbies': ['.NET', 'LOLCATS']
  }"), 
schema).Dump();

IsValid(JObject.Parse(
@"{
    'name': 2,
    'hobbies': ['.NET', 'LOLCATS']
  }"), 
schema).Dump();
}

public bool IsValid(JObject obj, JsonSchema schema)
{
    return obj.IsValid(schema);
}

output :-

True
False
False

You could also add "required":true to the fields that must be supplied that way you can return a message with details of missing/invalid fields:-

Property 'surname' has not been defined and the schema does not allow additional     properties. Line 2, position 19. 
Required properties are missing from object: name. 

Invalid type. Expected String but got Integer. Line 2, position 18. 
Andy Robinson
  • 7,309
  • 2
  • 30
  • 20
  • 2
    Instead of using "additionalProperties" for that purpose, it is currently encouraged to use "propertyNames" (since draft-06). It will do exactly the same job (allow only properties with keys enlisted in enum cor conforming to a pattern). See also: https://json-schema.org/understanding-json-schema/reference/object.html#property-names and consider: `"propertyNames" : { "enum" : ["name", "hobbies"] }` in your schema instead of "additionalProperties". – PsychoFish Nov 16 '18 at 12:20
4

Ok i hope this will help.

This is your schema:

 public class test
{
    public string Name { get; set; }
    public string ID { get; set; }

}

This is your validator:

/// <summary>
    /// extension that validates if Json string is copmplient to TSchema.
    /// </summary>
    /// <typeparam name="TSchema">schema</typeparam>
    /// <param name="value">json string</param>
    /// <returns>is valid?</returns>
    public static bool IsJsonValid<TSchema>(this string value)
        where TSchema : new()
    {
        bool res = true;
        //this is a .net object look for it in msdn
        JavaScriptSerializer ser = new JavaScriptSerializer();
        //first serialize the string to object.
        var obj = ser.Deserialize<TSchema>(value);

        //get all properties of schema object
        var properties = typeof(TSchema).GetProperties();
        //iterate on all properties and test.
        foreach (PropertyInfo info in properties)
        {
            // i went on if null value then json string isnt schema complient but you can do what ever test you like her.
            var valueOfProp = obj.GetType().GetProperty(info.Name).GetValue(obj, null);
            if (valueOfProp == null)
                res = false;
        }

        return res;
    }

And how to use is:

string json = "{Name:'blabla',ID:'1'}";
        bool res = json.IsJsonValid<test>();

If you have any question please ask, hope this helps, please take into consideration that this isn't a complete code without exception handling and such...

Shaun Groenewald
  • 866
  • 1
  • 17
  • 34
Liran
  • 591
  • 3
  • 13
  • 1
    Hi, thanks for the reply. The thing is (as I understand how your code works, if my understanding is wrong or there is another way to do it please explain) we don't have a C# class/object of the shcema. It is a schema string that is stored in the DB. There can be lots and lots of different schemas so we can't make objects for them all. – Shaun Groenewald Oct 24 '13 at 05:56
  • that is why i asked if schema is string only or can be object, i will try to make changes to match your needs. – Liran Oct 24 '13 at 08:04
  • @ShaunGroenewald hey sorry have had a lot of time lately, problem solved? – Liran Oct 27 '13 at 08:45
  • Hi, no I have not solved it yet. I was trying a string/regex find and compare on the two strings. – Shaun Groenewald Oct 28 '13 at 07:14
  • Yeah but I am a bit stuck at the moment. My thinking was doing a regex match on the key:value and put that into a list then compare the 2 lists to each other (if incoming json key name does not match any in the schema it is invalid) – Shaun Groenewald Oct 28 '13 at 14:25
  • @ShaunGroenewald and if schema is {Name:"liran",LastName:"B"} and json is {LastName:"B",Name:"liran"} ? that would be invalid... – Liran Oct 30 '13 at 14:16
  • Hi, no that should be fine. Compare incoming JSON vs List of schema properties. The order shouldn't matter, only that the element in the incoming string is in the schema list. – Shaun Groenewald Oct 31 '13 at 06:07
  • JSON schema validation is more complex than simply checking for the existence of all properties: https://spacetelescope.github.io/understanding-json-schema/ – Ohad Schneider Sep 21 '17 at 11:24
4

I am just adding short answer, using JSchemaGenerator from Newtonsoft.Json.Schema

 public static bool IsJsonValid<TSchema>>(string value)
    {
        JSchemaGenerator generator = new JSchemaGenerator();
        JSchema schema = generator.Generate(typeof(TSchema));
        schema.AllowAdditionalProperties = false;           

        JObject obj = JObject.Parse(value);
        return obj.IsValid(schema);
    }
0
public static class RequestSchema
{ 
    public static bool Validate<T>(string requestBody)
    {
        JSchemaGenerator generator = new JSchemaGenerator();
        JSchema schema = generator.Generate(typeof(T));
        JObject jsonObject = JObject.Parse(requestBody);
        bool isValid = jsonObject.IsValid(schema);
        return isValid;
    }
}

And call Method
RequestSchema.Validate<Person>(requestBody)

Reference https://www.newtonsoft.com/jsonschema
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 11 '23 at 23:19
  • Is this functionality available only in the paid version of `www.newtonsoft.com/jsonschema`? – PersianIronwood Mar 13 '23 at 15:03