Reputation: 351
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"]
}
Upvotes: 17
Views: 44769
Reputation: 1086
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.
Upvotes: 43
Reputation: 1271
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
}
Upvotes: 8