Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to output field as an array of json values? #449

Closed
MaerF0x0 opened this issue Aug 31, 2017 · 7 comments
Closed

how to output field as an array of json values? #449

MaerF0x0 opened this issue Aug 31, 2017 · 7 comments

Comments

@MaerF0x0
Copy link

If it makes it easier they can be the "simple" types (number, bool, null, string ... not array or object)

I'm trying to send a message like

my.proto:

Items {
 repeated <what here?> data =1;
}

I would like it to be
{"items":{"data": ["hi", 123, false, null]}}

bytes gives me a base64 encoded string
repeated bytes gives me an array of base64 encoded strings

@MaerF0x0 MaerF0x0 changed the title how to say a field is an array of any json value? how to output field as an array of json values? Aug 31, 2017
@MaerF0x0
Copy link
Author

It looks like maybe? https://godoc.org/github.com/golang/protobuf/ptypes/struct#ListValue Just figuring out how to use it now.

@MaerF0x0
Copy link
Author

ListValue did it. It looks like one probably can use those types to force whatever json kinds one wants @yugui Do you want me to contrib some docs to help the next person?

@tmc
Copy link
Collaborator

tmc commented Sep 1, 2017

@MaerF0x0 a documentation addition for this would be /super/ helpful for other folks down the line. Please do!

@achew22
Copy link
Collaborator

achew22 commented Sep 5, 2017

@MaerF0x0, to echo Travis' comment, even a code snippet in here would be really interesting to see. Thanks for digging in!

I'm going to close this PR since it seems you've got it figured out but I would like to see if it's possible to add some docs on this.

@achew22 achew22 closed this as completed Sep 5, 2017
@MaerF0x0
Copy link
Author

So I finally figure how to abuse grpc-gateway to make it have the HTTP interface we want, but now the go code is heinous. :-/

syntax = "proto3";

package somesvc;

import "google/api/annotations.proto";
import "google/protobuf/struct.proto";

service SomeSvc {
  rpc OutgoingListValues(Nil) returns (stream SomeListValues) {
    option (google.api.http) = {
      get: "/listvalue"
    };
  }

  rpc IncomingListValues(SliceListValues) returns (Nil) {
    option (google.api.http) = {
      post: "/listvalue"
      body: "*"
    };
  }

}

message Nil {}

message SliceListValues{
  repeated google.protobuf.ListValue rows = 1;  // json => {"rows": [["a", 1, true, null],...]}
}

message SomeListValues{
  google.protobuf.ListValue row = 1;  // stream of json => {"row": ["a", 1, true, null]}
}

but the outgoing go looks like this (absurd).

	srv.Send(&somesvc.SomeListValues{
		Row: &structpb.ListValue{
			Values: []*structpb.Value{
				&structpb.Value{Kind: &structpb.Value_StringValue{StringValue: "a"}},
				&structpb.Value{Kind: &structpb.Value_NumberValue{NumberValue: 1.0}},
				&structpb.Value{Kind: &structpb.Value_BoolValue{BoolValue: false}},
				&structpb.Value{Kind: &structpb.Value_NullValue{NullValue: structpb.NullValue_NULL_VALUE}},
			},
		},
	})

ideally it would just be:

	srv.Send([]interface{}{"a", 1.0, true, nil})

@MaerF0x0
Copy link
Author

@achew22 Let me know if you'd like some docs surrounding ^^? I learned how to use the google well known types to make GRPC-gateway have the interface I like, but it also means the GRPCServer interface becomes gnarly.

@achew22
Copy link
Collaborator

achew22 commented Oct 16, 2017

I'm not 100% sure on this since I can't see your code, but I would bet that you could create a helper method much like proto.String (or the other types) like this:

func StringValue(v string) *structpb.StringValue {
  return &structpb.StringValue(Kind: &structpb.Value_StringValue{StringValue: "a"}})
}
// ... et al

Usage might look like:

	srv.Send(&somesvc.SomeListValues{
		Row: &structpb.ListValue{
			Values: []*structpb.Value{
				StringValue("a"},
				NumberValue(1.0),
				BoolValue(false),
				NullValue(null), // enums are hard and you might have to check if the value is nil here instead of doing it on type.
			},
		},
	})

Or you could write an even more high level abstraction to translate from (I wouldn't do this, it feels kind of icky)

func (r *Receiver) func SendIt(srv Yourtype, v []interface{}) {
	r := &somesvc.SomeListValues{
		Rows: &structpb.ListValue{
			Values: []*structpb.Value{},
		}
	}
	for _, k := range v {
		switch s := v.(type) {
		case string:
			r.Rows.Values = append(r.Rows.Values, &structpb.Value_StringValue{StringValue: s}}
			break
		// ... More types
		case default:
			panic("This is unimplemented so bail")
	}
	return r.srv.Send(r)
}

That said, you're not forced to use go as your langage for server writing. If you think you can do better in python, c++, javascript or any of the other gRPC languages you can write your server in that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants