Ganesh Agrawal
Ganesh Agrawal

Reputation: 11

Unmarshalling json into protobuf having oneof type

I'm working on something that has api definition defined complying with openapi 3.0.0 Asper openapi 3.0.0, the oneOf type field can take value of any one of the mentioned type.

pet:
  oneOf:
    - $ref: '#/components/schemas/Cat'
    - $ref: '#/components/schemas/Dog'
components:
  schemas:
    Dog:
      type: object
      properties:
        bark:
          type: boolean
        breed:
          type: string
          enum: [Dingo, Husky, Retriever, Shepherd]
    Cat:
      type: object
      properties:
        hunts:
          type: boolean
        age:
          type: integer

As per swagger, the correct json schema for this can be {"pet":{"hunts":false,"age":3}} if the pet type is cat, and if it's a dog, it will be {"pet":{"bark":true,"breed":"Husky"}}

It doesn't explicitly specify the type, and assumes that the server can decode it depending on the fields present.

I am using protobuf to manage the data types since i also need to send this to different microservices using grpc, for this kind of example i thought of using oneOf from proto.

the definition of the proto is

message pet{
oneof pet{
Cat cat = 1;
Dog dog = 2;
}
}
message Cat {
boolean hunts = 1;
int age = 2;
}
message Dog {
boolean bark = 1;
string breed =2;
}

But unmarshling the json into pet type fails since it's expecting the json message has to have a field pet, and then dog or cat i guess.

Is there any other convention followed for the oneof type from openapi spec to golang?

Is there any other convention followed for the oneof type from openapi spec to golang?

Upvotes: 1

Views: 288

Answers (1)

DazWilkin
DazWilkin

Reputation: 40296

You're correct the the JSON equivalent of the Protobuf example you provide does not match the OpenAPI:

[
  {
    "dog":{
      "bark":true,
      "breed":"Border Collie"
    }
  },
  {
    "cat":{
      "hunts":true,
      "age":4
    }
  }
]

You could consider using Google's Well-known Types, specifically Value

message M {
    google.protobuf.Value pet = 1;
}

Unfortunately, you lose the type-safety that Protobuf wants to enforce using oneof but, you get the (typeless) JSON that you want:

[
  {
    "pet":{
      "bark":true,
      "breed":"Border Collie"
    }
  },
  {
    "pet":{
      "hunts":true,
      "age":4
    }
  }
]

Upvotes: 0

Related Questions