25

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.

4
  • do you want to validate string(schema) vs. string(given object) or could you use an object as schema? Commented Oct 23, 2013 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. Commented Oct 23, 2013 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? Commented Oct 23, 2013 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. Commented Oct 23, 2013 at 14:37

4 Answers 4

20

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. 
Sign up to request clarification or add additional context in comments.

1 Comment

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: json-schema.org/understanding-json-schema/reference/… and consider: "propertyNames" : { "enum" : ["name", "hobbies"] } in your schema instead of "additionalProperties".
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...

8 Comments

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.
that is why i asked if schema is string only or can be object, i will try to make changes to match your needs.
@ShaunGroenewald hey sorry have had a lot of time lately, problem solved?
Hi, no I have not solved it yet. I was trying a string/regex find and compare on the two strings.
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)
|
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);
    }

2 Comments

This is the most elegant solution in this post, thanks Dhananjay!
Is this functionality available only in the paid version?
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

2 Comments

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.
Is this functionality available only in the paid version of www.newtonsoft.com/jsonschema?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.