Bu örnekte, istemci isteklerine ve sunucu yanıtlarına üstbilgiler (header) ekleyeceğiz. İstemci istek üstbilgileri gönderir ve sunucu üstbilgilerle yanıt verir. Her iki uçta da başlıkları çıkaracağız.


Örnek


Burada ilgisiz olduğu için proto dosyasını göstermeyeceğim.


İstemci


package main

import (
"context"
"log"
"strings"
"time"

"pkg/proto/user"

"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)

func main() {
log.Println("Client running ...")

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

conn, err := grpc.Dial(":50051", grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalln(err)
}
defer conn.Close()

client := user.NewDeleteServiceClient(conn)

request := &user.DeleteRequest{Uuid: "UUID-123"}

// Anything linked to this variable will transmit request headers.
md := metadata.New(map[string]string{"x-request-id": "req-123"})
ctx = metadata.NewOutgoingContext(ctx, md)

// Anything linked to this variable will fetch response headers.
var header metadata.MD

response, err := client.Delete(ctx, request, grpc.Header(&header))
if err != nil {
log.Fatalln(err)
}

xrid := header["x-response-id"]
if len(xrid) == 0 {
log.Fatalln("missing 'x-response-id' header")
}
if strings.Trim(xrid[0], " ") == "" {
log.Fatalln("empty 'x-response-id' header")
}

log.Println(response.GetCode())
log.Println(xrid[0])
}

Sunucu


package main

import (
"context"
"log"
"net"
"strings"

"pkg/proto/user"

"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)

type server struct {
user.UnimplementedDeleteServiceServer
}

func main() {
log.Println("Server running ...")

lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalln(err)
}

srv := grpc.NewServer()
user.RegisterDeleteServiceServer(srv, &server{})

log.Fatalln(srv.Serve(lis))
}

func (s *server) Delete(ctx context.Context, request *user.DeleteRequest) (*user.DeleteResponse, error) {
// Anything linked to this variable will fetch request headers.
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, status.Errorf(codes.DataLoss, "failed to get metadata")
}
xrid := md["x-request-id"]
if len(xrid) == 0 {
return nil, status.Errorf(codes.InvalidArgument, "missing 'x-request-id' header")
}
if strings.Trim(xrid[0], " ") == "" {
return nil, status.Errorf(codes.InvalidArgument, "empty 'x-request-id' header")
}

log.Println(request.GetUuid())
log.Println(xrid[0])

// Anything linked to this variable will transmit response headers.
header := metadata.New(map[string]string{"x-response-id": "res-123"})
if err := grpc.SendHeader(ctx, header); err != nil {
return nil, status.Errorf(codes.Internal, "unable to send 'x-response-id' header")
}

return &user.DeleteResponse{Code: 123}, nil
}

Test


$ go run client/main.go 

2020/04/08 21:50:17 Client running ...
2020/04/08 21:50:17 123
2020/04/08 21:50:17 res-123 # Test with full header
2020/04/08 21:51:32 missing 'x-response-id' header # Test without header
2020/04/08 21:51:32 empty 'x-response-id' header # Test with empty header

$ go run server/main.go 

2020/04/08 21:49:35 Server running ...
2020/04/08 21:49:39 UUID-123
2020/04/08 21:49:39 req-123