I want to handle messages like this in protobuf:
Python code:
request_proto = PrettyRequest()
Parse(body, request_proto)
I have an error:
Message type "some_path.PrettyList" has no field named "driver_activity_v1_2". Available Fields(except extensions): ['entities']
How to fix protobuf structure?
Json-body example
{
"my_services": {
"service1": {
"entities": {
"driver_id":[1001, 1003]
}
},
"serviceN": {
"entities": {
"driver_id":[1, 2]
}
}
}
}
My proto file:
message PrettyRequest {
PrettyList my_services = 1;
}
message PrettyList {
map<string, EntitiesDict> entities = 1;
}
message EntitiesDict {
map<string, RepeatedValue> entities = 1;
}
message RepeatedValue {
repeated Value val = 1;
}
message Value {
// ValueType is referenced by the metadata types, FeatureInfo and EntityInfo.
// The enum values do not have to match the oneof val field ids, but they should.
// In JSON "*_val" field can be omitted
oneof val {
bytes bytes_val = 1;
string string_val = 2;
int32 int32_val = 3;
}
}
There are at least 2 ways that you can achieve this.
Generally (!) using JSON as a template for a Protobuf schema is challenging because JSON is weakly typed whereas Protobuf messages are strongly-typed.
syntax="prpto3";
message X {
map<string,Y> my_services = 1;
}
message Y {
repeated int32 driver_id = 1;
}
x = foo_pb2.X(
my_services={
"service1":foo_pb2.Y(
driver_id=[1001,1003]
),
"serviceN":foo_pb2.Y(
driver_id=[1,2]
)
}
)
json_string = json_format.MessageToJson(x,preserving_proto_field_name=True)
print(json_string)
NOTE I've used
X
andY
as placeholders.
Yields:
{
"my_services": {
"serviceN": {
"driver_id": [
1,
2
]
},
"service1": {
"driver_id": [
1001,
1003
]
}
}
}
NOTE This matches your JSON sample.
Google Well-known Types include Value
which can be used to represent arbitrary (any type) JSON objects.
from google.protobuf import json_format
from google.protobuf.struct_pb2 import Value
v = Value()
j = '''{
"my_services": {
"service1": {
"entities": {
"driver_id":[1001, 1003]
}
},
"serviceN": {
"entities": {
"driver_id":[1, 2]
}
}
}
}'''
# print(j)
json_format.Parse(j,v)
# print(v)
json_string = json_format.MessageToJson(v)
print(json_string)
Yields:
{
"my_services": {
"serviceN": {
"entities": {
"driver_id": [
1.0,
2.0
]
}
},
"service1": {
"entities": {
"driver_id": [
1001.0,
1003.0
]
}
}
}
}
NOTE This matches your JSON sample.
The main challenges with using Value
are that (a) the Protobuf message structure is complicated; (b) the Protobuf message structure accepts any JSON not just messages from types inferred from your JSON sample.