How to extract specific values from a response?

34 views
Skip to first unread message

yoges nsamy

unread,
Aug 26, 2020, 1:21:46 AM8/26/20
to grpc.io

I have the following response from a grpc call:
&{id:"4" topic:"fnd" sub:<updated_at:1588240740070 acs:<> public:"{"fn":"Yogeswari","pn":"Yoges"}" private:"["mhub:e995b6be-b528-4d1b-9e52-cdcca7ebf4d6"]" user_id:"usr4M22x6F-Fq4" > }

It is returned by res.GetMessage.
go func() {
       // function to receive a bunch of messages
       for {
           res, err := stream.Recv()
           if err == io.EOF {
               break
           }
           if err != nil {
               log.Fatalf("Error while receiving: %v", err)
               break
           }
           fmt.Printf("Received: %v\n", res.GetMessage())
       }
       close(waitc)
   }()

I need to extract the user_id from the response and I'm able to do it the following way:
msg := fmt.Sprintf("%v", res.GetMessage())
           s := strings.Index(msg, "user_id:")
           if s != -1 {
               s += len("user_id:")
               e := strings.Index(msg, " > }")
               if e != -1 {
                   fmt.Printf("pos: %s", msg[s:e])
               }
           }

What is the right way to extract the response? How can I assign the result to a struct (or something else) for easy access in the rest of the code?

Apology if I'm using some incorrect terms in the question. I'm new to both golang and grpc.

Thank you for reading.

ericgr...@google.com

unread,
Aug 26, 2020, 1:20:14 PM8/26/20
to grpc.io
Hi,

If I understand correctly, you are asking about how to access fields in your proto message. There is a getting started with protobufs for Go at https://developers.google.com/protocol-buffers/docs/gotutorial#the_protocol_buffer_api, but for your specific question you should be able to retrieve the user id via the `res.UserId` field on the response message.

Thanks,

Eric

yoges nsamy

unread,
Aug 26, 2020, 10:55:48 PM8/26/20
to ericgr...@google.com, grpc.io
Thank you for your response.

I tried res.UserId but it doesn't work with the error:
'res.UserId undefined (type *pbx.ServerMsg has no field or method UserId)':
image.png

The code is in a bi-directional stream call. Sharing the code below:
fmt.Println("Starting get by cognito id RPC...")
enableCors(&w)

crtFile := "/home/yogesnsamy/Coding/MHub/prod_cert/cert.crt"
creds, err := credentials.NewClientTLSFromFile(crtFile, "")
if err != nil {
log.Fatal("Error loading cert", err)
}

conn, err := grpc.Dial("dev.mhub.my:16060", grpc.WithTransportCredentials(creds))
if err != nil {
log.Fatal("Error dialing", err)
}

c := pbx.NewNodeClient(conn)
// we create a stream by invoking the client
stream, err := c.MessageLoop(context.Background())
if err != nil {
log.Fatalf("Error while creating stream: %v", err)
return
}

// get user's cognito user id
cuID, ok := req.URL.Query()["cid"]

if !ok || len(cuID[0]) < 1 {
log.Println("Url Param 'cid' is missing")
return
}
fmt.Println("cuid is ", cuID[0])
tag := fmt.Sprintf(`"%v"`, cuID[0]) // mhub
fmt.Println(tag)

requests := []*pbx.ClientMsg{
&pbx.ClientMsg{
Message: &pbx.ClientMsg_Hi{Hi: &pbx.ClientHi{
Id: "1",
UserAgent: "Golang_Spider_Bot/3.0",
Ver: "0.15",
Lang: "EN",
}},
},
&pbx.ClientMsg{
Message: &pbx.ClientMsg_Login{Login: &pbx.ClientLogin{
Id: "2",
Scheme: "basic",
Secret: []byte("carol:carol123"),
}},
},
&pbx.ClientMsg{
Message: &pbx.ClientMsg_Sub{
Sub: &pbx.ClientSub{
Id: "3",
Topic: "fnd",
GetQuery: &pbx.GetQuery{
What: "sub",
},
},
},
},
&pbx.ClientMsg{
Message: &pbx.ClientMsg_Set{Set: &pbx.ClientSet{
Id: "4",
Topic: "fnd",
Query: &pbx.SetQuery{
Desc: &pbx.SetDesc{
Public: []byte(tag),
},
},
},
},
},
&pbx.ClientMsg{
Message: &pbx.ClientMsg_Get{Get: &pbx.ClientGet{
Id: "5",
Topic: "fnd",
Query: &pbx.GetQuery{
What: "sub",
},
}},
},
}

waitc := make(chan struct{})
// we send a bunch of messages to the client (go routine)
go func() {
// function to send a bunch of messages
for _, req := range requests {
fmt.Printf("Sending message: %v\n", req)
stream.Send(req)
time.Sleep(1000 * time.Millisecond)
}
stream.CloseSend()
}()
// we receive a bunch of messages from the client (go routine)
go func() {
// function to receive a bunch of messages
for {
res, err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("Error while receiving: %v", err)
break
}
rid := res.GetCtrl()
fmt.Printf("Id: %v\n", rid)

msg := fmt.Sprintf("%v", res.GetMessage())
s := strings.Index(msg, "user_id:")
if s != -1 {
s += len("user_id:")
e := strings.Index(msg, " > }")
if e != -1 {
fmt.Printf("pos: %s", msg[s:e])
}
}
res.UserId
fmt.Printf("res.Message >> %v\n", res.Message)

}
close(waitc)
}()

// block until everything is done
<-waitc

ServerMsg is defined as below - UserId is not defined in this struct.
Will I have to update some code on the grpc server prior to accessing the value from the client?
Appreciate some guidance.
image.png


--
You received this message because you are subscribed to the Google Groups "grpc.io" group.
To unsubscribe from this group and stop receiving emails from it, send an email to grpc-io+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/grpc-io/31a067b9-89b8-48c4-82fb-956c29e541d1n%40googlegroups.com.

Eric Gribkoff

unread,
Aug 27, 2020, 1:01:10 AM8/27/20
to yoges nsamy, grpc.io
The ServerMsg struct is in a 1:1 correspondence with the ServerMsg proto definition. The proto does not have a user_id field, as you point out, so neither does the generated Go data structure. I'm finding it a little hard to at-a-glance assess the overall structure of your protos, but the `oneof` means that exactly one of those fields will be set in the ServerMsg proto/struct. Your code indicated that the ServerMsg has its ctrl field set (this line), in which case I think you are retrieving the user ID from its map of strings (defined here). I'm not that familiar with Go, but now I think I understand the original question a bit better now: no, you should not have to format the entire proto message as a string in order to access this map data. Here is the relevant documentation section for Go protos: https://developers.google.com/protocol-buffers/docs/reference/go-generated#map

Something like res.GetCtrl().Params will get you access to the proto-defined map as a Golang map.

Thanks,

Eric

yoges nsamy

unread,
Aug 27, 2020, 7:49:37 AM8/27/20
to Eric Gribkoff, grpc.io
Appreciate the detailed explanation!
I'm able to better understand the proto definition after reading your message.

Sharing a sample code below on how I can iterate through the values inside Params (for others just starting out in Go like me)
p := res.GetCtrl().Params
for key, element := range p {
fmt.Println("Key:", key, "=>", "Element:", string(element))
}
Reply all
Reply to author
Forward
0 new messages