This is a very annoying problem, and one that we hit a lot in my project (
https://github.com/deepmap/oapi-codegen), where we generate Go models from
OpenAPI specs, and the OpenAPI "AnyOf" or "OneOf" schema does precisely
this.

You can partially unmarshal; store your "type" field in a typed variable,
and use json.RawMessage to defer parsing to later, when you know the type.
This still gets annoying, because if your field names are dynamic, you need
to override the default unmarshaling behavior to produce a map of field
names to json.RawMessage. If you jump through these hoops, you can avoid
parsing twice. Once you've partially parsed your object, you can create
some functions on it, such as "AsAtype()" or "AsBType()", which switches on
"type" and returns the correct concrete object.

On Mon, Dec 26, 2022 at 10:04 AM Andrew Burian <and...@burian.dev> wrote:

> Hey all, wondering if there's an existing best practice for this so I'm
> not reinventing the wheel.
>
> It's frustratingly common to have APIs where the response JSON can be one
> of several distinct objects, and the indicator of which object has been
> returned is itself a property of the object.
>
> So you might get a `{ "type": "aType", "aField" : ."..." }` or a `{
> "type": "bType", "bField": "..." }` response from the same API.
>
> What's the best way to deserialize in these situations?
>
> Ideas I've tried so far:
>
>    - Unmarhsal twice, once into a struct that just defines the `Type`
>    property and ignores all other fields, then again based on the type set the
>    first time.
>    Works, but for large objects it's extremely wasteful.
>
>    - Unmarshal into a large struct that defines all possible subtypes as
>    anonymous struct fields so their declarations are treated as being on the
>    outer struct, then cast to the appropriate type after unmarshaling to mask
>    all the unfilled fields.
>    Again, works, but feels awful. It also presents a real issue when you
>    need to verify that no fields other than the expected fields for the given
>    type were present, which you can usually do with
>    Decoder.DisallowUnknownFields, but silently succeeds if one of the fields
>    is valid for a different object type.
>
> I'm trying to do this as much with stdlib as possible. I've looked into
> some other libraries that make heavy use of JSON decoding and have seen
> both my above ideas, as well as just entirely custom Unmarshaller
> implementations. Hopefully it doesn't come to that.
>
> Cheers,
> Andrew
>
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAPyCRsvvzzscpgfjj2vPQAi5_DVvrfhxLMu_OhuETzKAd7N1xQ%40mail.gmail.com
> <https://groups.google.com/d/msgid/golang-nuts/CAPyCRsvvzzscpgfjj2vPQAi5_DVvrfhxLMu_OhuETzKAd7N1xQ%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CA%2Bv29LsE8iu%3DN%3Dm%2BGFZMGdVT7ALDvdprQZArMcoicDusKZ9ZYw%40mail.gmail.com.

Reply via email to