Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JsonSchemaGenerator Not Setting Fields to required = false

I'm using a JsonSchemaGenerator from JSON.NET against a series of models to output the respective JSON schemas into a dictionary like below.

JsonSchemaGenerator generator = new JsonSchemaGenerator()
{
    UndefinedSchemaIdHandling = UndefinedSchemaIdHandling.UseTypeName,
};
List<Type> modelTypes = Assembly.GetExecutingAssembly()
    .GetTypes()
    .ToList()
    .Where(t => t.Namespace == "MyApp.Models")
    .ToList();

foreach (Type type in modelTypes)
{
    JsonSchema schema = generator.Generate(type, jsonSchemaResolver, false);
    schemaDictionary.Add(type, schema);
}

This is working properly with the exception of the vales set for the required attribute. No matter how I decorate the model properties, the fields always are shown to be "required":true as shown below:

"FirstName": {
   "required": true,
   "type": "string"
}

However, in code my model is decorated as such:

[JsonProperty(Required = Required.Default)]
public string FirstName { get; set; }

Looking at the Json.Net documentation, setting to Required.Default should result in the property not being required in the schema:

"Default - 0 - The property is not required. The default state."

Any idea on what I'm doing incorrectly and need to change so that FirstName property is output in the schema as "required": false? I do not want to have to generate and hand massage all of these schemas.

like image 433
atconway Avatar asked Aug 21 '14 15:08

atconway


1 Answers

The Required enumeration controls which values can the property have: whether null values are allowed or not. To control the "required" property in the json schema, meaning whether the json string must contain the actual property or not, you need to use the DefaultValueHandling or NullValueHandling enumerations while generating the schema. Lets say that we have the following class:

public class Person
{
        [JsonProperty(Required = Required.Default)]
        public string FirstName { get; set; }    
}

Generated schema with JSON.NET for this class looks like this:

{
    "id": "MyApp.Models.Person",
    "type": "object",
    "properties": {
        "FirstName": {
            "required": true,
            "type": [
                "string",
                "null"
            ]
        }
    }
}

This schema indicates that a json string must have the property FirstName and it is allowed for this property to have null values.

By changing the Required attribute from Default to Always we'll get the following schema:

{
    "id": "MyApp.Models.Person",
    "type": "object",
    "properties": {
        "FirstName": {
            "required": true,
            "type": "string"
        }
    }
}

This schema indicates that a json string must have the property FirstName and it is NOT allowed for this property to have null values.

To get what you want, you'll need to include the DefaultValueHandling or NullValueHandling enumerations. Something like this:

public class Person
{
    [JsonProperty(Required = Required.Default, DefaultValueHandling = DefaultValueHandling.Ignore)]
    public string FirstName { get; set; }    
}

Generated schema from this class would look like this:

{
    "id": "MyApp.Models.Person",
    "type": "object",
    "properties": {
        "FirstName": {
            "type": [
                "string",
                "null"
            ]
        }
    }
}

This schema indicates that the FirstName property is not required in the json string, but if it is present, it may have null value. The same effect can be achieved if you use DefaultValueHandling.IgnoreAndPopulate enum value or if you switch to the NullValueHandling property instead of DefaultValueHandling property and set its value to NullValueHandling.Ignore.

like image 77
Ilija Dimov Avatar answered Oct 16 '22 07:10

Ilija Dimov