json unmarshalling troubles

129 views
Skip to first unread message

natxo....@gmail.com

unread,
Jun 2, 2021, 9:15:50 AM6/2/21
to golang-nuts
hi,

I have this json back from an api:

{
    "all_parameters": [{
            "priority": 60,
            "created_at": "2021-06-02 12:15:13 UTC",
            "updated_at": "2021-06-02 12:15:13 UTC",
            "id": 28,
            "name": "network_interface_mapping",
            "parameter_type": "yaml",
            "value": {
                "interface1": "eno1",
                "interface2": "eno2",
                "interface3": "eno3",
                "interface4": "eno4"
            }
        },
        {
            "priority": 60,
            "created_at": "2021-06-02 12:15:13 UTC",
            "updated_at": "2021-06-02 12:15:13 UTC",
            "id": 27,
            "name": "component_1",
            "parameter_type": "boolean",
            "value": true
        },
        {
            "priority": 50,
            "created_at": "2021-03-19 14:34:26 UTC",
            "updated_at": "2021-03-19 14:34:26 UTC",
            "id": 15,
            "name": "url1",
            "parameter_type": "string",
            "value": "http://www.example.org/1"
        }
    ]
}

If I use the json2go service, then it simplifies the values like this:


type Autogenerated struct {
             AllParameters []struct {
                   Priority int `json:"priority"`
                   CreatedAt string `json:"created_at"`
                   UpdatedAt string `json:"updated_at"`
                   ID int `json:"id"` Name string `json:"name"`
                   ParameterType string `json:"parameter_type"`
                   Value struct {
                          Interface1 string `json:"interface1"`
                          Interface2 string `json:"interface2"`
                          Interface3 string `json:"interface3"`
                          Interface4 string `json:"interface4"`
                          } `json:"value"`
                } `json:"all_parameters"`
}

so the value struct has the values of just the first parameter, in fact. The other parameters have different values, could be a boolean or a string.

How can I use this in my client script? Unmarhalling into this struct type gives me obviously errors

 Error: json: cannot unmarshal object into Go struct field .all_parameters.value of type string

Thanks in advance for your input.

Regards,
Natxo

Robert Glonek

unread,
Jun 2, 2021, 11:02:36 AM6/2/21
to golang-nuts
The json is not very strict, while go is. It would be good if the json struct could potentially be strictly of same type all over the place. Implementing parser for this json in any language will be a bit of a pain with some try/except...

If you really need to do so, you would need to have the Value as type interface{} and then use Reflect to find out if it's a struct, or bool or int and cast it accordingly to it's type. But really, would be easier if the value field was uniform, no matter the language used.

So in other words:
1. unmarshal using interface
2. reflect to find type
3. cast to a new variable for the select type

type Autogenerated struct { 
             AllParameters []struct { 
                   Priority  int  `json:"priority"`
                   CreatedAt  string `json:"created_at"` 
                   UpdatedAt  string `json:"updated_at"` 
                   ID  int  `json:"id"` Name  string `json:"name"` 
                   ParameterType string `json:"parameter_type"` 
                   Value  interface{} `json:"value"` 
                   valueAsInt int
                   valueAsBool bool
                   valueAsMap map[string]interface{}
                } `json:"all_parameters"` 
}

Example here:

Robert Glonek

unread,
Jun 2, 2021, 11:12:21 AM6/2/21
to golang-nuts
Here's a quick-glued reflect example.


If you try using switch value.(type) instead of using reflect, bool will be reported as int, fyi, so using reflect here.

Brian Candler

unread,
Jun 2, 2021, 11:22:34 AM6/2/21
to golang-nuts
> If you try using switch value.(type) instead of using reflect, bool will be reported as int, fyi, so using reflect here.

Could you explain that a bit further please?  A type switch seems to work OK for me, with no reflect.

Robert Glonek

unread,
Jun 2, 2021, 2:55:40 PM6/2/21
to golang-nuts
I think I'm loosing my marbles. Nevermind what I said.

Amnon

unread,
Jun 3, 2021, 1:41:21 AM6/3/21
to golang-nuts
No, whoever designed the schema of this API has lost their marbles,
(or lacks any kind of consideration for the unfortunate souls who need to use this API).

Unmarshalling a value whose type is not fixed is a pain in Go.
But handling a value of unknown type will be a headache in any language.

natxo....@gmail.com

unread,
Jun 3, 2021, 4:04:48 AM6/3/21
to golang-nuts

hi all,

thanks for your insights. The Value interface{}  type does work nicely.

I had tried as well the map[string]interface{} route, and it works as well, so now I have two solutions which is kind of a luxury position.

Regards,
Natxo
Reply all
Reply to author
Forward
0 new messages