I get a response from an external API that has a field which can have 2 values:
{"field": []}
or
{"field": {"key1": "value", "key2": "value"}}
I set the struct to be
type Object Struct {
Field map[string]string `json:"field,omitempty"`
}
And then call my own implemented function to decode the response
func decode(response *http.Response) (*Object, error) {
var response Object
err := json.NewDecoder(response.Body).Decode(&response)
if err != nil {
return nil, err
}
return &response, nil
}
But this works only for the second response ( when field not empty is). For the first response I get an error.
CodePudding user response:
Rename the variable response inside decode function. Since both function argument & variable declared are of same name, it creates confusion.
CodePudding user response:
you can do a custom marshaler type for the Field. Example:
type keys struct {
Key1 string
Key2 string
}
type mytype struct {
EmptySlice bool
Keys *keys
}
func (m *mytype) UnmarshalJSON(b []byte) error {
if bytes.Equal(b, []byte("[]")) {
m.EmptySlice = true
return nil
}
m.Keys = &keys{}
return json.Unmarshal(b, &m.Keys)
}
type Object struct {
Field mytype `json:"field"`
}
func main() {
input := []string{
`{"field": []}`,
`{"field": {"key1": "value", "key2": "value"}}`,
}
for i, s := range input {
var o Object
err := json.Unmarshal([]byte(s), &o)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d: % v\n", i 1, o)
}
}
https://go.dev/play/p/OqSKfUXHFyb
CodePudding user response:
You can use a custom type and implement the UnmarshalJSON interface method on that type.
For example:
type Field struct {
arr []string
m map[string]string
}
func (f *Field) UnmarshalJSON(b []byte) error {
var m map[string]string
err := json.Unmarshal(b, &m)
if err == nil {
f.m = m
return nil
}
var arr []string
err = json.Unmarshal(b, &arr)
if err == nil {
f.arr = arr
return nil
}
return fmt.Errorf("type of property not array or map")
}
