Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can I check that a JSON value is an object with the keys I need?

Quick answer

With .NET's System.Text.Json, check the root JsonElement.ValueKind against JsonValueKind.Object first. If it is not an object, report that and stop; only then use TryGetProperty for each required key and report missing names. These checks establish the root type and key presence, not whether the values have the right types or meaningful contents.

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have JSON loaded as a JsonDocument. How do I make sure its top-level value is an object before checking fields?

Geez

Check document.RootElement.ValueKind before looking up any properties. In System.Text.Json, ValueKind identifies the kind of the current JSON value; comparing the root with JsonValueKind.Object tells you whether the top level is an object. [S1]

For example, assume your application requires the keys name and email. Those are illustrative schema choices, not requirements imposed by JSON. If the root is an array, string, number, or another non-object value, report the root-type problem and stop that validation path. Do not call TryGetProperty on it: that method is for an object, and calling it on another kind can throw InvalidOperationException. [S2]

Follow-up question

Once the root passes, how do I report missing keys instead of failing at the first one?

Geez

Call TryGetProperty once for every required name, collect the names for which it returns false, and report that collection. It both searches the current object and indicates whether the named property exists. [S2] The example below returns a message for a wrong root kind or a list of missing keys:

using System;
using System.Collections.Generic;
using System.Text.Json;

static string? Validate(JsonElement root)
{
    if (root.ValueKind != JsonValueKind.Object)
        return $"Expected a JSON object; got {root.ValueKind}.";

    string[] required = { "name", "email" };
    var missing = new List<string>();

    foreach (string key in required)
    {
        if (!root.TryGetProperty(key, out _))
            missing.Add(key);
    }

    return missing.Count == 0
        ? null
        : $"Missing required keys: {string.Join(", ", missing)}.";
}

Here, null means the two checks passed; adapt that return convention to your application. The root-kind check happens first, so the property checks run only on an object.

Follow-up question

Does a key count as present if its value is null, or if the spelling has different capitalization?

Geez

A key with a JSON null value is present: TryGetProperty checks whether the property exists, not whether its value is non-null, correctly typed, or useful. [S2] If null is not allowed, add a separate value check after the key is found. Similarly, the documented string overload matches property names using ordinal, case-sensitive comparison, so Name does not satisfy a required key named name. [S2]

The example therefore validates presence only. It does not establish that name is a string, that email is non-empty, or that either value meets your application's rules. Those checks need a separate schema-specific step.

Follow-up question

What should I look at when testing this validator, so I know it reports both kinds of problem clearly?

Geez

Try a non-object root, an object with all required keys, and an object missing one or both. For example, with the assumed keys name and email, [] should produce the wrong-root message, while { "name": "Ada" } should report email as missing. An object containing both keys with null values passes this particular presence check; that result is expected, not proof the values are acceptable.

Keep the error distinction visible in your application: a wrong root is a type problem, while missing names are property-presence problems. The API documentation supports these .NET checks; it does not define your required keys or value rules. Decide those from your own input contract.

A practical checklist

  • Define the required property names for your input contract.

  • Check that the root ValueKind is Object before property lookup.

  • If the root is not an object, report that problem and stop this check.

  • Use TryGetProperty for every required name and collect all missing names.

  • Validate value types, nullability, and content separately if your contract requires them.

  • Test a wrong-kind root, a complete object, and objects with missing keys.

A few more useful answers

Does this check validate nested objects too?

No. It checks only the root and the required top-level keys shown. Validate nested values separately if your input contract requires them.

Can I use this example with any JSON library or programming language?

No. JsonElement, ValueKind, and TryGetProperty are .NET System.Text.Json APIs. The cited documentation does not establish equivalent behavior for other libraries.

What does an empty missing-key list prove?

It proves only that the required property names were found on the checked object. It does not prove that their values have acceptable types or contents.

Sources

References used for this guide.

  1. [S1] JsonElement.ValueKind Property (System.Text.Json)
    learn.microsoft.com · Checked
  2. [S2] JsonElement.TryGetProperty Method (System.Text.Json)
    learn.microsoft.com · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work