Check if JSON is Object or Array

Use the following to detect if JSON text in the []byte value data is an array or object:

 // Get slice of data with optional leading whitespace removed.
 // See RFC 7159, Section 2 for the definition of JSON whitespace.
 x := bytes.TrimLeft(data, " \t\r\n")

 isArray := len(x) > 0 && x[0] == '['
 isObject := len(x) > 0 && x[0] == '{'

This snippet of code handles optional leading whitespace and is more efficient than unmarshalling the entire value.

Because the top-level value in JSON can also be a number, string, boolean or nil, it's possible that isArray and isObject both evaluate to false. The values isArray and isObject can also evaluate to false when the JSON is invalid.


Use a type switch to determine the type. This is similar to Xay's answer, but simpler:

var v interface{}
if err := json.Unmarshal(data, &v); err != nil {
    // handle error
}
switch v := v.(type) {
case []interface{}:
    // it's an array
case map[string]interface{}:
    // it's an object
default:
    // it's something else
}

Do step-by-step parsing of your JSON, using json.Decoder. This has the advantage over the other answers of:

  1. Being more efficient than decoding the entire value
  2. Using the official JSON parsing rules, and generating standard errors if you get invalid input.

Note, this code isn't tested, but should be enough to give you the idea. It can also be easily expanded to check for numbers, booleans, or strings, if desired.

func jsonType(in io.Reader) (string, error) {
    dec := json.NewDecoder(in)
    // Get just the first valid JSON token from input
    t, err := dec.Token()
    if err != nil {
        return "", err
    }
    if d, ok := t.(json.Delim); ok {
        // The first token is a delimiter, so this is an array or an object
        switch (d) {
        case '[':
            return "array", nil
        case '{':
            return "object", nil
        default: // ] or }, shouldn't be possible
            return "", errors.New("Unexpected delimiter")
        }
    }
    return "", errors.New("Input does not represent a JSON object or array")
}

Note that this consumed the first few bytes of in. It is an exercise for the reader to make a copy, if necessary. If you're trying to read from a byte slice ([]byte), convert it to a reader first:

t, err := jsonType(bytes.NewReader(myValue))

Go playground