How to represent a mix of enum and oneof in protobuf - protocol-buffers

I am trying to create a protocol buffer message with fields that are either a message or one of a choice of some constant (like an enum). Something that is logically equivalent to:
message Error {
oneof error_type {
EMPTY_METHOD_NAME = 0
ExecutionError execution_error = 1;
}
message ExecutionError {
string value = 1;
}
}
Essentially, I would like a field that can represent either an error type that is just a name with no fields, or an error type that has fields. How would I do this with protobuf3?

See Enumerations in the Language Guide (proto3)
message Error {
oneof error_type {
Foo foo = 1;
ExecutionError execution_error = 2;
}
enum Foo {
X = 0;
Y = 1;
Z = 2;
}
message ExecutionError {
string value = 1;
}
}

Related

Parse nested (opaque, any-typed) Protobuf message

I have a message envelope:
import "google/protobuf/any.proto";
message Envelope {
string type = 1;
int32 version = 2;
string message_id = 5;
string timestamp = 6;
google.protobuf.Any message = 7;
}
Now, I happen to know that the message is another Protobuf value with the following type:
And a message defined as follows:
message Message {
int32 value = 1;
string name = 2;
}
Is it possible for me to do a one-shot parsing of this combined message? I am thinking that the problem with substituting Any with Message is the field numbering.
Any is just:
message Any {
string type_url = 1;
bytes value = 2;
}
where the value is just the regular payload content. If you know that the type is your Message, then you can use instead
message Envelope {
string type = 1;
int32 version = 2;
string message_id = 5;
string timestamp = 6;
FakeAny message = 7;
}
message FakeAny {
// don't even need to capture the type_url
Message value = 2;
}
message Message {
int32 value = 1;
string name = 2;
}
and it should deserialize directly.

Protobuf different messages for the same field

is it possible to create a field that can hold different types of messages? Let's say I wanted to send a request to create a car, but it can have different types of windows in it, and each type requires different fields to be present:
message TintedWindows {
double tintPercent = 1;
string tintColor = 2;
}
message ArmoredWindows {
string armorClass = 1;
}
message CreateCarRequest {
string color = 1;
int wheels = 2;
int doors = 3;
Windows??? windows = 4;
}
Is there a way of doing that smoothly or I have to add all those messages and check which one is empty and which one is not:
message CreateCarRequest {
string color = 1;
int wheels = 2;
int doors = 3;
TintedWindows tinted = 4;
ArmoredWindows armored = 5;
}
then do: (pseudocode)
windowsInterface windows;
if req.tinted != null && req.armored == null {
windows = newTinted(req.tinted)
} else if req.tinted == null && req.armored != null {
windows = newArmored(req.armored)
} else {
throw error
}
I'm curently doing that using the second method and it's a bit cumbersome.
You can use Oneof.
message CreateCarRequest {
string color = 1;
uint32 wheels = 2;
uint32 doors = 3;
oneof windows {
TintedWindows tinted = 4;
ArmoredWindows armored = 5;
}
}
There is no int type (see scalar), you'll need to choose one of the available types, probably uint32 for number of wheels and doors.

Protocol buffer split oneof message to a different file

I use nanopb and a .proto file that looks like this (simplified):
syntax = "proto3";
message Type1
{
bool a = 1;
}
message Type2
{
int32 b = 1;
}
message Message
{
int32 id = 1;
oneof oneMessage {
Type1 messageType1 = 2;
Type2 messageType2 = 3;
}
}
I now need to split the oneMessage to a different .proto file and import it. I can do something like:
file a.proto:
syntax = "proto3";
import "b.proto"
message Message
{
int32 id = 1;
oneofTypeMessage aMessage = 2;
}
file b.proto
syntax = "proto3";
message Type1
{
bool a = 1;
}
message Type2
{
int32 b = 1;
}
message oneofTypeMessage
{
oneof oneMessage {
Type1 messageType1 = 2;
Type2 messageType2 = 3;
}
}
But this means I can't get to my message types with message.messageType1, triggering lots of changes in the existing source code. How can I split the oneof part to another file without changing the way I access to it?
I've tried declaring Message in both files but it is not permitted.
No. oneMessage is not a message type, and to import something from another file, it must be a message type. Adding a new oneofTypeMessage would add an additional node in the graph, and would not be data-compatible with the original data.
You can move Type1 and Type2, but the oneof must stay as-was; so: this is valid:
file a.proto:
syntax = "proto3";
import "b.proto"
message Message
{
int32 id = 1;
oneof oneMessage {
Type1 messageType1 = 2;
Type2 messageType2 = 3;
}
}
file b.proto:
syntax = "proto3";
message Type1
{
bool a = 1;
}
message Type2
{
int32 b = 1;
}

oneof CustomType protobuf

I am tyring to replicate python schema code to golang(protobuf). I am stuck in 1 of the condition.
message Type1 {
enum Type{
type1 = 1
}
Type type = 0;
string name = 1;
}
message Type2 {
enum Type{
type2 = 1
}
Type type = 0;
string name = 1;
repeated string value = 2;
}
message Type3 {
enum Type{
time = 1
}
Type type = 0;
string name = 1;
string format = 2;
string value = 3;
}
message Request {
something
something
map<string, oneof_above_defined_types> params = n
}
How do i make sure that map takes only custom types defined above?
I think you'll need to define a new type that includes the oneof type:
message TypeX {
oneof type_oneof {
Type1 type_1 = 1;
Type2 type_2 = 2;
Type3 type_3 = 3;
};
}
message Request {
...
map<string, TypeX> params = n;
}

How to define empty parameter for Protocol Buffers rpc method?

I have a method that I would like defined called FindAll which requires no parameters. ProtoC is complaining.
Expected type name.
This is for line:
rpc findAll () returns (BenchmarksList);
syntax = "proto3";
package helloWorldGRPC;
service HelloWorldGRPCService {
rpc findById (BenchmarksById) returns (Benchmarks);
rpc findAll () returns (BenchmarksList);
}
message BenchmarksById {
string id = 1;
}
message BenchmarksList {
repeated Benchmarks benchmarks = 1;
}
message Benchmarks {
string trans_id = 1;
string protocol = 2;
string database = 3;
string updated_at = 4;
string created_at = 5;
repeated Action actions = 6;
}
message Action {
string trans_id = 1;
int32 payload_length = 2;
string payload = 3;
string status = 4;
string updated_at = 5;
string created_at = 6;
}
The preferred way is to pass Empty - as tooling may recognize and optimize for that scenario. But in reality, there is nothing "special" about that type and any message - empty or otherwise - will suffice.

Resources