2

I am getting a big nested json object from an external api. I want to make sure all fields are populated in that json object. Is there any libray available to do that? Newtonsoft.Json has JToken class which checks if the Json's schema is valid or not but i don't find any method to check if all the fields inside json object are filled.

Scenario : I am building an api which gathers information about a person or entity. there are numerous sources of information. I need to continue searching for the data until the required object is full. So first call goes to api1, gets some data, checks if object is full. If object is not full then goes to api2 and so on. So the call returns after the object is full. One key point is that the required object schema is not static.

I could deserialize it to a POCO and loop through each nested object but i am looking for a better solution.

Any suggestion is highly appreciated.

Venkata Dorisala
  • 4,783
  • 7
  • 49
  • 90
  • 1
    You could use `RequireObjectPropertiesContractResolver` from [Json.NET require all properties on deserialization](https://stackoverflow.com/a/29660550/3744182). It's unclear from your question whether you want [`Required.Always` or `Required.AllowNull`](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Required.htm). – dbc Oct 20 '17 at 17:53
  • I need `Required.Always`. So it checks while deserializing ? Does it applicable to children as well ? – Venkata Dorisala Oct 20 '17 at 17:54
  • Is there anyway to achieve the same result without deserializing the json ? – Venkata Dorisala Oct 20 '17 at 17:58
  • *So it checks while deserializing?* Yes. *Does it applicable to children as well ?* Yes. The advantage of using a custom contract resolver is that it applies to all types being deserialized, without any need to manually add properties to those types. *Is there anyway to achieve the same result without deserializing the json?* Json.NET determines the set of expected properties by looking at the contract for the type being deserialized. How else would you want to specify the set of required properties? Or do you just want all JSON properties to be non-null? – dbc Oct 20 '17 at 18:20
  • Yes, i want all json properties inside the object to be not null.. I am developing an api which gets information from other apis. it keeps looking for next apis until it gets all information required.. so i need to check if the object is full each time and continue to next api or return if object is full. – Venkata Dorisala Oct 20 '17 at 18:27

2 Answers2

3

If I understood you correctly, you have some complex JSON object, with a set of required and not-required properties.

I see here three solutions:

  1. You've already mentioned JSON schema validation. Here is one of the implementations: Json.NET Schema.
  2. Create a POCO object and mark all properties with corresponding Required/Not-Required attributes. In this case, you'll get exceptions if a json-string doesn't contain any mandatory data. For example, how it's done in terms of Json.NET's JsonPropertyAttribute:

    [JsonObject]
    public class PocoObject
    {
        [JsonProperty("$schema", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)]
        public string Schema { get; set; }
    
        [JsonProperty("name", Required = Required.Always)]
        public string Name { get; set; }
    
        [JsonProperty("properties", Required = Required.Always)]
        public MorePropertiesObject Properties { get; set; }
    }
    

    As a bonus, you can add your custom attributes, methods, converters, etc

  3. Deserialize raw json into a Dictionary-like structure and validate it with your own hands-written validator. Something like:

    try
    {
        var jo = JObject.Parse(jsonString);
        Contract.Assert(!string.IsNullOrEmpty(jo["root"]["prop1"].ToString()));
        Contract.Assert(!string.IsNullOrEmpty(jo["root"]["prop2"].ToString()));
    }
    catch (JsonReaderException) { }
    catch (JsonSerializationException) { }
    

Provided code samples are for mentioned by you Newtonsoft.Json

Ihor Kliushnikov
  • 388
  • 1
  • 5
  • 10
  • Thanks Ihor. But the response json object is not static. it varies and all properties inside that object are required. So if i pass a random json object it should return me if all the properties are filled or not. – Venkata Dorisala Oct 20 '17 at 18:35
  • @Venky, dbc proposed an enhanced version of my 3rd variant, and it should suit your problem. Keep in mind, that if you need to validate empty arrays too, you have to add one more check into `AnyNull()` method (arrays in Json.net represented with `JArray` object. – Ihor Kliushnikov Oct 21 '17 at 04:00
2

If you have a JSON string and simply want to check whether any property value or array item are null, you can parse to a JToken, recursively descend the JToken hierarchy with JContainer.DescendantsAndSelf(), and check each JValue for being null using the following extension method:

public static partial class JsonExtensions
{
    public static bool AnyNull(this JToken rootNode)
    {
        if (rootNode == null)
            return true;
        // You might consider using some of the other checks from JsonExtensions.IsNullOrEmpty()
        // from https://stackoverflow.com/questions/24066400/checking-for-empty-null-jtoken-in-a-jobject
        return rootNode.DescendantsAndSelf()
            .OfType<JValue>()
            .Any(n => n.Type == JTokenType.Null);
    }

    public static IEnumerable<JToken> DescendantsAndSelf(this JToken rootNode)
    {
        if (rootNode == null)
            return Enumerable.Empty<JToken>();
        var container = rootNode as JContainer;
        if (container != null)
            return container.DescendantsAndSelf();
        else
            return new[] { rootNode };
    }
}

And then do:

var root = JToken.Parse(jsonString);
var anyNull = root.AnyNull();

If you just want to check for null property values (i.e. null values in an array are OK) you can use the following extension method:

public static partial class JsonExtensions
{
    public static bool AnyNullPropertyValues(this JToken rootNode)
    {
        if (rootNode == null)
            return true;
        return rootNode.DescendantsAndSelf()
            .OfType<JProperty>()
            .Any(p => p.Value == null || p.Value.Type == JTokenType.Null);
    }
}

(It isn't entirely clear from your question which you want.)

Sample .Net fiddle.

dbc
  • 104,963
  • 20
  • 228
  • 340