How to get custom field value in pb.go - go

There's a defined .proto file. syntax: proto3.
syntax = "proto3";
package proto;
import "google/protobuf/descriptor.proto";
extend google.protobuf.ServiceOptions {
string api_prefix = 50001;
}
extend google.protobuf.MethodOptions {
string api_url = 50002;
string api_method = 50003;
}
option go_package = "proto;proto";
service Foo {
option (api_prefix) = "/math";
rpc Add(MathRequest) returns (MathResponse) {
option (api_url) = "/:number1/:number2";
option (api_method) = "PUT";
}
}
message MathRequest {
string number1 = 1;
string number2 = 2;
}
message MathResponse {
string number = 1;
}
And there's a .pb.go file generated by protoc --go_out=. *.proto
How can I get api_url option value in services, and api_url option value in RPC method?

I got a solution myself.
var fd protoreflect.FileDescriptor
fd = pb.File_math_proto
s := fd.Services().Get(0)
m := s.Methods().Get(0).Options()
n := proto.GetExtension(m, pb.E_Http)
e := n.(*pb.HttpRule)

Related

How to represent a mix of enum and oneof in protobuf

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;
}
}

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;
}

How do I assign value to a repeated oneof field in a protobuf message?

I have a protobuf message CoverageReport like this:
message Deductible {
double amount = 1;
string currency = 2;
}
message Insurance{
string type = 1;
string policyNumber = 2;
string agreementName = 3;
string appliedTo = 4;
string validFrom = 5;
string validTo = 6;
Deductible deductible = 7;
}
message Warranty {
string type = 1;
string warrantyType = 2;
string agreementName = 3;
string appliedTo = 4;
string validFrom = 5;
string validTo = 6;
}
message Coverage {
oneof item {
Insurance insurance = 1;
Warranty warranty = 2;
}
}
message CoverageReport {
bool coverageAppliance = 1;
repeated Coverage coverages = 2;
}
In my program I'm trying to assign values to a message instance, but I'm not sure how to assign to the oneof field Coverage which should then be appended to Coverages, like this
I get a response from an api, which i unmarshal into the struct CoverageReport which has similar structure to the protobuf. Then i need to create a protobuf message using the values from the struct. But it doesn't seem to work to asssign to the one of field!
type CoverageReport struct {
CoverageAppliance string `json:"coverageAppliance"`
Coverages []struct {
Type string `json:"type"`
PolicyNumber string `json:"policyNumber,omitempty"`
AgreementName string `json:"agreementName"`
AppliedTo string `json:"appliedTo"`
ValidFrom string `json:"validFrom"`
ValidTo string `json:"validTo"`
Deductible struct {
Amount float64 `json:"amount"`
Currency string `json:"currency"`
} `json:"deductible,omitempty"`
WarrantyType string `json:"warrantyType,omitempty"`
} `json:"coverages"`
}
var coveragereport *CoverageReport
err = json.Unmarshal(body, &coveragereport)
var cr *vcsproto.CoverageReport
if coveragereport.CoverageAppliance == "Yes" {
cr.CoverageAppliance = true
}
for _, item := range coveragereport.Coverages {
if item.Type == "Warranty"{
var warranty *vcsproto.Warranty
warranty.Type = item.Type
warranty.WarrantyType = item.WarrantyType
warranty.AgreementName = item.AgreementName
warranty.AppliedTo = item.AppliedTo
warranty.ValidFrom = item.ValidFrom
warranty.ValidTo = item.ValidTo
var coverage *vcsproto.Coverage
coverage.Item.Warranty = warranty
cr.Coverages = append(cr.Coverages, coverage)
} else {
var insurance *vcsproto.Insurance
insurance.Type = item.Type
insurance.PolicyNumber = item.PolicyNumber
insurance.AgreementName = item.AgreementName
insurance.AppliedTo = item.AppliedTo
insurance.ValidFrom = item.ValidFrom
insurance.ValidTo = item.ValidTo.
insurance.Deductible.Currency = item.Deductible.Currency
insurance.Deductible.Amount = item.Deductible.Amount
var coverage *vcsproto.Coverage
coverage.Item.Insurance = Insurance
cr.Coverages = append(cr.Coverages, coverage)
}
}
Take a look in the generated code here.
You do not assign directly to the Warranty nor Insurance subfields, but directly to the Item field. so coverage.Item = {insurance/warranty} should work.
Also note that in your code you're assigning coverage.Item.Insurance = Insurance - you probably meant the second Insurance to be the variable insurance instead.

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.

In a proto, how can I define a map as a custom option

In my proto file, I want to define a map as a custom option, tried a few things but none is working.
my metadata proto file:
syntax = "proto2";
import "google/protobuf/descriptor.proto";
package com.util;
option java_package = "com.util";
message MyMeta {
optional bool needValidation = 1;
map<string, string> fileMap = 2;
}
extend google.protobuf.FieldOptions {
optional MyMeta meta = 80412;
}
my proto file
syntax = "proto3";
package com.test;
import "util/meta.proto";
import "google/protobuf/timestamp.proto";
message MyMeta {
int32 id = 1 [(com.util.meta).needValidation = false, /*looking for a way to set a map (com.meta).tableOptions = {"t,raw_orders"}]*/;
}
Is this possible?
This works:
message MyMeta {
int32 id = 1 [
(com.util.meta) = {
needValidation: false,
fileMap: [
{
key: "t",
value: "raw_orders"
}
];
}];
}
The protobuf map is syntactic sugar for a repeated field of map entry messages with key and value fields. 1
In your case, your meta message
message MyMeta {
optional bool needValidation = 1;
map<string, string> fileMap = 2;
}
is equivalent to
message MyMeta {
optional bool needValidation = 1;
message FileMapEntry {
string key = 1;
string value = 2;
}
repeated FileMapEntry fileMap = 2;
}
Of course, it would be much nicer if there was a more obvious way to specify a map value in an option.
Seems it is not possible. To make my logic, I created a string like "StoreOrders:raw_orders_test,OrderItems:raw_order_items_test
message MyMeta {
int32 id = 1 [(com.util.meta).needValidation = false, (com.meta).tableOptions = "TableA:valueA,TableB:valueB;
}
and in my jav code and splitting the string to create a hash map.

Resources