How to read metadata (passed as a header) on the server side in grpc? Any example in golang?
I am writing something like this:
// this should be passed from the client side as a context and needs to accessed on server side to read the metadata
var headers = metadata.New(map[string]string{"authorization": "", "space": "", "org": "", "limit": "", "offset": ""})
I want to pass the Authorization token to my validation function to validate the received token.
func validate_token(ctx context.Context, md *metadata.MD) (context.Context, error){
token := headers["authorization"]
}
Metadata is represented as key/value pairs, where the key is a string and the value is either a string or binary data. You don't need to specify metadata in the . proto file. Metadata is handled by the Metadata class of the Grpc.
Multiple gRPC clients can be created from a channel, including different types of clients. A channel and clients created from the channel can safely be used by multiple threads. Clients created from the channel can make multiple simultaneous calls.
Yes, you can definitely do that.
gRPC - vehicle for a real-time full-duplex communication.
original answer is correct but reading the headers is slightly outdated
import "google.golang.org/grpc/metadata"
func (s myServer) MyMethod(ctx context.Context, *Request) (*Response, error) {
var values []string
var token string
md, ok := metadata.FromIncomingContext(ctx)
if ok {
values = md.Get("authorization")
}
if len(values) > 0 {
token = values[0]
}
// do something with token
}
You have to insert your metadata into the client's context before calling the server.
For an unary RPC the client side looks like:
conn, _ := grpc.Dial(address, opts...)
client := NewMyClient(conn) // generated from your proto with the grpc protoc option
header := metadata.New(map[string]string{"authorization": "", "space": "", "org": "", "limit": "", "offset": ""})
// this is the critical step that includes your headers
ctx := metadata.NewContext(context.Background(), header)
request := // construct a request for your service
response, err := client.MyMethod(ctx, request)
For a stream, it looks almost the same:
conn, _ := grpc.Dial(address, opts...)
client := NewMyClient(conn) // generated from your proto with the grpc protoc option
header := metadata.New(map[string]string{"authorization": "", "space": "", "org": "", "limit": "", "offset": ""})
// this is the critical step that includes your headers
ctx := metadata.NewContext(context.Background(), header)
stream, err := client.MyMethodStream(ctx)
for {
request := // construct a request for your service
err := stream.Send(request)
response := new(Response)
err = stream.RecvMsg(response)
}
On the server side for an unary RPC:
func (s myServer) MyMethod(context.Context, *Request) (*Response, error) {
md, ok := metadata.FromIncomingContext(ctx)
token := md.Get("authorization")[0] // metadata.Get returns an array of values for the key
}
and for a streaming RPC:
func (s myServer) MyMethodStream(stream MyMethod_MyServiceStreamServer) error {
md, ok := metadata.FromIncomingContext(stream.Context())
token := md.Get("authorization")[0] // metadata.Get returns an array of values for the key
for {
request := new(Request)
err := stream.RecvMsg(request)
response := // do work
err := stream.SendMsg(response)
}
}
Note that for a stream there are only three times that headers can be sent: in the context used to open the initial stream, via grpc.SendHeader, and grpc.SetTrailer. It is not possible to set headers on arbitrary messages in a stream. For an unary RPC header are sent with every message and can be set in the initial context, with grpc.SendHeader and grpc.SetHeader, and grpc.SetTrailer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With