Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unmarshal a custom struct when the JSON value given is not a JSON object

Tags:

json

go

I have a custom struct defined that I'm using to Unmarshal an API response into. Sometimes, the API decides to send an empty string ("") when the object is empty or missing. I'm unclear how to handle this type mismatch. I actually have hundreds of these custom structs (nested) and the API will do this for the top-most parent if it is empty. If there is some way to do this globally without the need for a custom UnmarshalJSON method, that would be ideal. I'm using code generation, so I could add those methods easily.

When I first attempted to write my own custom UnmarshalJSON, I ended up in a loop:

func (e MyStruct) UnmarshalJSON(b []byte) error {
    t := MyStruct{}
    if string(b) == `""` {e = t} else {
        if err := json.Unmarshal(b, e); err != nil {
            return fmt.Errorf("failed to parse nested structure: %v", err)
        }
    }
    return nil
}

I understand why I ended up in the loop, but I have a feeling there is a better solution I'm missing.

I've created an example in the Go Playground.

https://play.golang.org/p/DrrFhA3TzPv

My current, generated code is here if you're looking for more context: https://github.com/mbrancato/edgeos/blob/a8af9143aa82ddece27089bf2f543f473c97d2db/sdk/config.go

like image 639
mike_b Avatar asked Nov 28 '25 03:11

mike_b


1 Answers

Use the following code to unmarshal the value.

var emptyString = []byte(`""`)

func (e *MyStruct) UnmarshalJSON(b []byte) error {
    if bytes.Equal(b, emptyString) {
        *e = MyStruct{}
        return nil
    }
    type t MyStruct
    if err := json.Unmarshal(b, (*t)(e)); err != nil {
        return fmt.Errorf("failed to parse nested structure: %w", err)
    }
    return nil
}

Notes:

  • UnmarshalJSON must be on pointer receiver.
  • Avoid recursion by declaring new type t with same underlying type as MyStruct. Unmarshal to a value of type t.
  • Compare bytes instead of string to avoid allocations.
  • To allow use of errors.As in the caller, use %w as the formatting verb for the error.
like image 71
3 revsuser13631587 Avatar answered Nov 30 '25 21:11

3 revsuser13631587