How to add message type as object in ProtoBuf (gRPC) - Proto3 Syntax? - protocol-buffers

How to send message type as object in ProtoBuf - Proto3 Syntax?
I want to transfer object instead of string or number.
Example
{
name: 'One',
date: 'date',
some: 'some',
...
...
}
syntax = "proto3";
package db;
service Proxy
{
rpc myFunction(Request) returns (Response);
}
message Request
{
string name = 1;
}
message Response
{
object keyvalue = 1;
}
Here, I am getting error
throw Error("no such Type or Enum '" + path + "' in " + this);
^
Error: no such Type or Enum 'object' in Type
--
Workaround
I can convert it to string in server side, and then I can JSON.parse() at client.
But I want to know, if there any better way to do it.

protocol-buffer does not support the object data type!
But you can emulate your data as hierarchically by using protocol buffer message type itself.
syntax = "proto3";
package db;
service Proxy
{
rpc myFunction(Request) returns (Response);
}
message Request
{
string name = 1;
}
message Response
{
message obj {
string key1 = 1;
string key2 = 2
}
obj keyvalue = 1; // Here you have created your own type obj.
}
In the above example, you can see that the Response message now has "keyvalue" field of type obj(which is a custom type you have just built).
Now you will pass Object in a callback from the server instead of primitive type.
callback(null, { keyvalue: { key1: "value1", key2: "value2" } });
Let's say if keys are unknown to you but key/value pair data type is same and known to you then, in this case, you can use
map<type, type>
message Response
{
map<string, string> keyvalue = 1;
}
callback(null, { keyvalue: { "key1": "value1", "key5": "value2" } });
References:-
https://developers.google.com/protocol-buffers/docs/proto3#other
https://developers.google.com/protocol-buffers/docs/proto#scalar
https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Struct

Depending on what you're trying to accomplish, you can likely use one of three types.
The bytes type represents an arbitrary string of bytes. You can choose to encode your types in anyway you feel appropriate.
The any type represents an arbitrary protobuf message, allowing the client or server to encode non-predefined messages. This is a string of bytes, with a unique identifier per message type and language implementations will have ways to unpack the message.
You mention using Javascript. You could likely define a Javascript object message using a combination of oneof for the basic types and map for object types.

If all of the keys and values you want to send have the same type, you can use a map type. Your example shows string keys and string values, so that could use the type map<string, string>.
If you want to send arbitrary object data with similar structure to JSON objects, you can use the google.protobuf.Struct message type.

Related

GO : Define a type which is Map with 2 specifique Key

I want to define a type Message which is basically a map[string]string with 2 specific keys : message and from.
A Message should be :
map[string]string{"message": "Hello", "from": "Me"}
I defined a type Message :
type Message struct {
message string,
from string
}
Note : I need to convert this Message to json in order to send it though http request, that's why I "need" to use map[string]string => I finnaly found out that it's also possible to serialized struct as JSON objects
It is possible to defined a type which is a map with specific key with go ?
What would be the idiomatic solution to do this in Go ?
As revealed in the comments on the question, the reason for preferring map[string]string is to preserve JSON encoding. However, structs can be serialized as JSON objects
import "json"
type Message struct {
Message string `json:"message"`
From string `json:"from"`
}
myMessage := Message{Message: "foo", From: "bar"};
serialized, err := json.Marshal(myMessage);
if err != nil {
// handle the error
}

How to create dynamic nested object message in protoBuff?

Am trying to create a message of nested dynamic objects
The resulting ending data structure should look like this
"content": {
"foo1": "bar1",
"foo2": "bar2"
}
Where the keys and, the values inside the content is dynamic and can be defined by the client.
You can define content as a map<string, string>, so that clients can set any arbitrary key-value pairs (of string type) to it.
message Msg {
map<string, string> content = 1;
}
If the value might be any arbitrary types, you can try google.protobuf.Struct.

How to cast lambda parameters in Optional

I have a lambda expression like below. What I want to ask is Is there any easy way or best practice for the casting the lambda parameter(x) to String?
Optional.ofNullable(result).isPresent( x-> {
String value = (String) x;
});
When I try to change input type like
String value = (String) x;
I am getting below error;
Inconvertible types; cannot cast the lambda parameter to java.lang.String
You could do a safe casting:
Optional.of(result)
.filter(String.class::isInstance) // verify that Object is a String
.map(String.class::cast) // safely cast to String
.ifPresent( input-> {
// now input is a String
});

grpc and protobuf with variable keys

I have a hash of key values pairs.
I do not have the keys, nor the values.
I can assume most will be there, but sometimes keys are removed and others are added. Is there any way for me to have a message with variable keys?
{
"knownkey1": "value",
"knownkey2": {
"unknown-key1": "value",
"unknown-key2": "value"
}
}
or is the best ways to just serialize it using json stringify in the message? i would think that would defeat the whole purpose of using grpc.
message Rate {
string ticker = 1;
string value = 2;
}
message GetAllResponse {
string lastUpdated = 1;
repeated Rate payload = 2;
}
Looks like you can just use the maps type as outlined here:
https://developers.google.com/protocol-buffers/docs/proto3#maps

Overriding "root" object value of GraphQL Union/Interface type

I have an Apollo GraphQL service that delegates to an internal gRPC service. This service has an endpoint which returns a message that contains a oneof, which I'm mapping to a Union in GraphQL.
This is straightforward, but there's a fair degree of boilerplate involved when implementing the resolvers. Suppose I have the following protobuf message definition:
message MyUnionMessage {
oneof value {
UnionType1 type1 = 1;
UnionType1 type2 = 3;
UnionType1 type3 = 4;
}
}
message UnionType1 {<type 1 props>}
message UnionType2 {<type 2 props>}
message UnionType3 {<type 3 props>}
My corresponding GraphQL schema looks something like this:
union MyUnionType = UnionType1 | UnionType2 | UnionType3
type UnionType1 {<type 1 props>}
type UnionType1 {<type 2 props>}
type UnionType1 {<type 3 props>}
In the javascript binding for gRPC, a MyUnionMessage object will have two properties: value which is a string indicating which type of value is contained, and a property named for the type. So, if I had a MyUnionMessage containing a UnionType2, for example, the object would look like this:
{
value: 'type2',
type2: {...}
}
This is nice for implementing __resolveType, since I can do a simple switch on the value in value, but I then have to write a resolver for all of the fields of all of the concrete types.
What I'm looking for is to be able to so something like this:
resolvers = {
MyUnionType: {
__resolveType(obj) {
switch(obj.value) {
case 'type1': return 'UnionType1';
case 'type2': return 'UnionType2';
case 'type3': return 'UnionType3';
default: return null;
},
__resolveValue(obj) {
return obj[obj.value];
},
},
};
Basically, I want to write a "resolver" at the level of the generic union (or interface) type that transforms the object before it's passed to the concrete resolver.
Is such a thing possible?
I'd wager that this sort of scenario is typically solved by transforming the data before it hits the __resolveType logic. For example, say you had a Query field that returned a list of MyUnionType. Your resolver for that field might look something like:
function resolve (arr) {
return arr.map(obj => {
return {
...obj[obj.value]
type: obj.value // or whatever field name that won't cause a collision
}
})
}
You then switch on type inside of __resolveType and you're good to go. Of course, that means if you have multiple fields that return a MyUnionType, you'll want to extract that logic into a utility function that can be used by each resolver.
I don't think there's not really a way to do what you're trying to do with the existing API. You could, of course, do something like this:
const getUnionType(obj) {
switch(obj.value) {
case 'type1': return 'UnionType1';
case 'type2': return 'UnionType2';
case 'type3': return 'UnionType3';
default: {
throw new Error(`Unrecognized type ${obj.value}`)
}
}
}
const resolvers = {
MyUnionType: {
__resolveType(obj) {
const type = getUnionType(obj)
Object.assign(obj, obj[obj.value])
return type
},
},
};
This works, but keep in mind it is a bit fragile since it assumes resolveType will always get the same root value as the resolve function, which could hypothetically change in the future.

Resources