how to decode a multi/single value in Json

Viewed 137

I want to decode a request JSON that the value of a field could be a single string or array (list).

I know how to parse if separately. but I'm looking for a way to have a dynamic decoder to parse both of them.

The value field in the JSON is the case I'm talking about

Sample for single-value:

{
    "filter":{
        "op":"IN",
        "field":"name",
        "value": "testDuplicate"
    }
}

Sample for multi-value:

{
    "filter":{
        "op":"IN",
        "field":"name",
        "value":["testDuplicate","tt"]
    }
}

Structs for single value:

type DocumentTypeSearchRequest struct {
    Filter   DocTypeFilter `json:"filter"`
}
type DocTypeFilter struct {
    Op    string `json:"op"`
    Field string `json:"field"`
    Value string `json:"value"`
}

Structs for multi-value:

type DocumentTypeSearchRequest struct {
    Filter   DocTypeFilter `json:"filter"`
}
type DocTypeFilter struct {
    Op    string `json:"op"`
    Field string `json:"field"`
    Value []string `json:"value"`
}  

One solution is to try to decode with one of them if failed use another one, but I'm not sure if that is the proper way to handle this problem.

1 Answers

You need a custom unmarshaler. I've talked about a similar situation in this video:

type Value []string

func (v *Value) UnmarshalJSON(p []byte) error {
    if p[0] == '[' { // First char is '[', so it's a JSON array
        s := make([]string, 0)
        err := json.Unmarshal(p, &s)
        *v = Value(s)
        return err
    }
    // else it's a simple string
    *v = make(Value, 1)
    return json.Unmarshal(p, &(*v)[0])
}

Playground link

With this definition of Value, your struct would become something like:

type DocTypeFilter struct {
    Op    string `json:"op"`
    Field string `json:"field"`
    Value Value  `json:"value"`
}

and now your Value field will always be a slice, but it may contain only a single value when your JSON input is a string, and not an array.

Related