1# Metadata
2
3gRPC supports sending metadata between client and server.
4This doc shows how to send and receive metadata in gRPC-go.
5
6## Background
7
8Four kinds of service method:
9
10- [Unary RPC](https://grpc.io/docs/guides/concepts.html#unary-rpc)
11- [Server streaming RPC](https://grpc.io/docs/guides/concepts.html#server-streaming-rpc)
12- [Client streaming RPC](https://grpc.io/docs/guides/concepts.html#client-streaming-rpc)
13- [Bidirectional streaming RPC](https://grpc.io/docs/guides/concepts.html#bidirectional-streaming-rpc)
14
15And concept of [metadata](https://grpc.io/docs/guides/concepts.html#metadata).
16
17## Constructing metadata
18
19A metadata can be created using package [metadata](https://godoc.org/google.golang.org/grpc/metadata).
20The type MD is actually a map from string to a list of strings:
21
22```go
23type MD map[string][]string
24```
25
26Metadata can be read like a normal map.
27Note that the value type of this map is `[]string`,
28so that users can attach multiple values using a single key.
29
30### Creating a new metadata
31
32A metadata can be created from a `map[string]string` using function `New`:
33
34```go
35md := metadata.New(map[string]string{"key1": "val1", "key2": "val2"})
36```
37
38Another way is to use `Pairs`.
39Values with the same key will be merged into a list:
40
41```go
42md := metadata.Pairs(
43    "key1", "val1",
44    "key1", "val1-2", // "key1" will have map value []string{"val1", "val1-2"}
45    "key2", "val2",
46)
47```
48
49__Note:__ all the keys will be automatically converted to lowercase,
50so "key1" and "kEy1" will be the same key and their values will be merged into the same list.
51This happens for both `New` and `Pairs`.
52
53### Storing binary data in metadata
54
55In metadata, keys are always strings. But values can be strings or binary data.
56To store binary data value in metadata, simply add "-bin" suffix to the key.
57The values with "-bin" suffixed keys will be encoded when creating the metadata:
58
59```go
60md := metadata.Pairs(
61    "key", "string value",
62    "key-bin", string([]byte{96, 102}), // this binary data will be encoded (base64) before sending
63                                        // and will be decoded after being transferred.
64)
65```
66
67## Retrieving metadata from context
68
69Metadata can be retrieved from context using `FromIncomingContext`:
70
71```go
72func (s *server) SomeRPC(ctx context.Context, in *pb.SomeRequest) (*pb.SomeResponse, err) {
73    md, ok := metadata.FromIncomingContext(ctx)
74    // do something with metadata
75}
76```
77
78## Sending and receiving metadata - client side
79
80Client side metadata sending and receiving examples are available [here](../examples/features/metadata/client/main.go).
81
82### Sending metadata
83
84There are two ways to send metadata to the server. The recommended way is to append kv pairs to the context using
85`AppendToOutgoingContext`. This can be used with or without existing metadata on the context. When there is no prior
86metadata, metadata is added; when metadata already exists on the context, kv pairs are merged in.
87
88```go
89// create a new context with some metadata
90ctx := metadata.AppendToOutgoingContext(ctx, "k1", "v1", "k1", "v2", "k2", "v3")
91
92// later, add some more metadata to the context (e.g. in an interceptor)
93ctx := metadata.AppendToOutgoingContext(ctx, "k3", "v4")
94
95// make unary RPC
96response, err := client.SomeRPC(ctx, someRequest)
97
98// or make streaming RPC
99stream, err := client.SomeStreamingRPC(ctx)
100```
101
102Alternatively, metadata may be attached to the context using `NewOutgoingContext`. However, this
103replaces any existing metadata in the context, so care must be taken to preserve the existing
104metadata if desired. This is slower than using `AppendToOutgoingContext`. An example of this
105is below:
106
107```go
108// create a new context with some metadata
109md := metadata.Pairs("k1", "v1", "k1", "v2", "k2", "v3")
110ctx := metadata.NewOutgoingContext(context.Background(), md)
111
112// later, add some more metadata to the context (e.g. in an interceptor)
113md, _ := metadata.FromOutgoingContext(ctx)
114newMD := metadata.Pairs("k3", "v3")
115ctx = metadata.NewContext(ctx, metadata.Join(metadata.New(send), newMD))
116
117// make unary RPC
118response, err := client.SomeRPC(ctx, someRequest)
119
120// or make streaming RPC
121stream, err := client.SomeStreamingRPC(ctx)
122```
123
124### Receiving metadata
125
126Metadata that a client can receive includes header and trailer.
127
128#### Unary call
129
130Header and trailer sent along with a unary call can be retrieved using function [Header](https://godoc.org/google.golang.org/grpc#Header) and [Trailer](https://godoc.org/google.golang.org/grpc#Trailer) in [CallOption](https://godoc.org/google.golang.org/grpc#CallOption):
131
132```go
133var header, trailer metadata.MD // variable to store header and trailer
134r, err := client.SomeRPC(
135    ctx,
136    someRequest,
137    grpc.Header(&header),    // will retrieve header
138    grpc.Trailer(&trailer),  // will retrieve trailer
139)
140
141// do something with header and trailer
142```
143
144#### Streaming call
145
146For streaming calls including:
147
148- Server streaming RPC
149- Client streaming RPC
150- Bidirectional streaming RPC
151
152Header and trailer can be retrieved from the returned stream using function `Header` and `Trailer` in interface [ClientStream](https://godoc.org/google.golang.org/grpc#ClientStream):
153
154```go
155stream, err := client.SomeStreamingRPC(ctx)
156
157// retrieve header
158header, err := stream.Header()
159
160// retrieve trailer
161trailer := stream.Trailer()
162
163```
164
165## Sending and receiving metadata - server side
166
167Server side metadata sending and receiving examples are available [here](../examples/features/metadata/server/main.go).
168
169### Receiving metadata
170
171To read metadata sent by the client, the server needs to retrieve it from RPC context.
172If it is a unary call, the RPC handler's context can be used.
173For streaming calls, the server needs to get context from the stream.
174
175#### Unary call
176
177```go
178func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
179    md, ok := metadata.FromIncomingContext(ctx)
180    // do something with metadata
181}
182```
183
184#### Streaming call
185
186```go
187func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
188    md, ok := metadata.FromIncomingContext(stream.Context()) // get context from stream
189    // do something with metadata
190}
191```
192
193### Sending metadata
194
195#### Unary call
196
197To send header and trailer to client in unary call, the server can call [SendHeader](https://godoc.org/google.golang.org/grpc#SendHeader) and [SetTrailer](https://godoc.org/google.golang.org/grpc#SetTrailer) functions in module [grpc](https://godoc.org/google.golang.org/grpc).
198These two functions take a context as the first parameter.
199It should be the RPC handler's context or one derived from it:
200
201```go
202func (s *server) SomeRPC(ctx context.Context, in *pb.someRequest) (*pb.someResponse, error) {
203    // create and send header
204    header := metadata.Pairs("header-key", "val")
205    grpc.SendHeader(ctx, header)
206    // create and set trailer
207    trailer := metadata.Pairs("trailer-key", "val")
208    grpc.SetTrailer(ctx, trailer)
209}
210```
211
212#### Streaming call
213
214For streaming calls, header and trailer can be sent using function `SendHeader` and `SetTrailer` in interface [ServerStream](https://godoc.org/google.golang.org/grpc#ServerStream):
215
216```go
217func (s *server) SomeStreamingRPC(stream pb.Service_SomeStreamingRPCServer) error {
218    // create and send header
219    header := metadata.Pairs("header-key", "val")
220    stream.SendHeader(header)
221    // create and set trailer
222    trailer := metadata.Pairs("trailer-key", "val")
223    stream.SetTrailer(trailer)
224}
225```
226