Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to read metadata in grpc on the server side? (golang example)

Tags:

go

grpc

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"]
}
like image 862
Sanket Avatar asked Feb 08 '17 15:02

Sanket


People also ask

What is metadata in gRPC?

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.

Can gRPC server handle multiple clients?

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.

Can a gRPC server also be a client?

Yes, you can definitely do that.

Is gRPC full duplex?

gRPC - vehicle for a real-time full-duplex communication.


2 Answers

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
}
like image 184
Joe B Avatar answered Sep 28 '22 00:09

Joe B


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.

like image 40
Zack Butcher Avatar answered Sep 27 '22 22:09

Zack Butcher