google.golang.org/grpc@v1.72.2/Documentation/grpc-metadata.md (about)

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