Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

gRPC is a modern open source high performance Remote Procedure Call (RPC) framework that can run in any environment. It can efficiently connect services in and across data centers with pluggable support for load balancing, tracing, health checking and authentication. It is also applicable in last mile of distributed computing to connect devices, mobile applications and browsers to backend services.



GrpcUI

Install

Code Block
brew install grpcui


Run against server

Code Block
grpcui -plaintext 127.0.0.1:50051 



Sample Code

Code Block
languagebash
titleSampleServerClient
collapsetrue
package main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/encodingexamples/helloworld/helloworld"
	"google.golang.org/grpc/reflection"
)

const (
	defaultAddress = "127.0.0.1:50051"
	serviceName    = "sample.Greeter"
	methodName     = "/sample.Greeter/SayHello"
)

func init() {
	encoding.RegisterCodec(jsonCodec{})
}

type HelloRequesttype greeterServer struct {
	Name string `json:"name"`
}

type HelloReply struct {
	Message   string `json:"message"`
	Timestamp string `json:"timestamp"`
}

type jsonCodec struct{}

func (jsonCodec) Marshal(v any) ([]byte, error) {
	return json.Marshal(v)
}

func (jsonCodec) Unmarshal(data []byte, v any) error {
	return json.Unmarshal(data, v)
}

func (jsonCodec) Name() string {
	return "json"
}

type greeterService interface {
	SayHello(context.Context, *HelloRequest) (*HelloReply, error)
}

type greeterServer struct{}

helloworld.UnimplementedGreeterServer
}

func (greeterServer) SayHello(_ context.Context, req *helloworld.HelloRequest) (*helloworld.HelloReply, error) {
	name := req.NameGetName()
	if name == "" {
		name = "friend"
	}

	return &helloworld.HelloReply{
		Message:   fmt.Sprintf("Hello, %s!", name),
		Timestamp: time.Now().Format(time.RFC3339),
	}, nil
}

var greeterServiceDesc = grpc.ServiceDesc{
	ServiceName: serviceName,
	HandlerType: (*greeterService)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "SayHello",
			Handler:    sayHelloHandler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "sample",
}

func sayHelloHandler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) {
	req := new(HelloRequest)
	if err := dec(req); err != nil {
		return nil, err
	}

	baseHandler := func(ctx context.Context, req any) (any, error) {
		return srv.(greeterService).SayHello(ctx, req.(*HelloRequest))
	}

	if interceptor == nil {
		return baseHandler(ctx, req)
	}

	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: methodName,
	}
	return interceptor(ctx, req, info, baseHandler)
}

func main() {
	mode := flag.String("mode", "server", "server or client")
	addr := flag.String("addr", defaultAddress, "address to listen on or connect to")
	name := flag.String("name", "gRPC", "name to send in client mode")
	flag.Parse()

	logger := log.New(os.Stderr, "grpc-sample: ", log.LstdFlags)

	switch *mode {
	case "server":
		if err := runServer(*addr, logger); err != nil {
			logger.Fatal(err)
		}
	case "client":
		if err := runClient(*addr, *name, logger); err != nil {
			logger.Fatal(err)
		}
	default:
		logger.Fatalf("unsupported mode %q, use server or client", *mode)
	}
}

func runServer(addr string, logger *log.Logger) error {
	lis, err := net.Listen("tcp", addr)
	if err != nil {
		return fmt.Errorf("listen on %s: %w", addr, err)
	}

	server := grpc.NewServer(grpc.ForceServerCodec(jsonCodec{}))
	serverhelloworld.RegisterServiceRegisterGreeterServer(&greeterServiceDescserver, greeterServer{})
	reflection.Register(server)

	logger.Printf("server listening on %s with reflection enabled", addr)
	return server.Serve(lis)
}

func runClient(addr, name string, logger *log.Logger) error {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	conn, err := grpc.DialContext(
		ctx,
		addr,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		grpc.WithBlock(),
		grpc.WithDefaultCallOptions(grpc.ForceCodec(jsonCodec{})),
	)
	if err != nil {
		return fmt.Errorf("connect to %s: %w", addr, err)
	}
	defer conn.Close()

	reqclient := &HelloRequest{Name: name}
	resp := new(HelloReplyhelloworld.NewGreeterClient(conn)
	ifresp, err := connclient.InvokeSayHello(ctx, methodName, req, resp);&helloworld.HelloRequest{Name: name})
	if err != nil {
		return fmt.Errorf("invoke %sSayHello: %w", methodName, err)
	}

	logger.Printf("response: %s (%s)", resp.Message, resp.TimestampGetMessage())
	return nil
}


References

...