04/04/2020 - GO
In this example we are going to create a simple gRPC client and server application. Simply the client is sending a request and receiving a response from server. I am not going to get into details of what gRPC and proto files but added some links to the bottom.
There are two important things. The first one is the client and server applications share the same protobuf file. The second one is, if you update the proto file, you must recompile it to reflect the changes to its *.pb.go
file.
go mod init github.com/YOU/bank
go get -u google.golang.org/grpc
# MacOS
brew install protobuf
go get -u github.com/golang/protobuf/protoc-gen-go
When you build a gRPC application, you first create a *.proto
file and compile it then start developing your application.
├── Makefile
├── client
│ └── main.go
├── go.mod
├── go.sum
├── pkg
│ └── proto
│ └── credit
│ ├── credit.pb.go
│ └── credit.proto
└── server
└── main.go
.PHONY: compile
compile: ## Compile the proto file.
protoc -I pkg/proto/credit/ pkg/proto/credit/credit.proto --go_out=plugins=grpc:pkg/proto/credit/
.PHONY: server
server: ## Build and run server.
go build -race -ldflags "-s -w" -o bin/server server/main.go
bin/server
.PHONY: client
client: ## Build and run client.
go build -race -ldflags "-s -w" -o bin/client client/main.go
bin/client
syntax = "proto3";
package credit;
message CreditRequest {
float amount = 1;
}
message CreditResponse {
string confirmation = 1;
}
service CreditService {
rpc Credit(CreditRequest) returns (CreditResponse) {}
}
I am not adding the content here because it is generated with the command above.
make compile
package main
import (
"context"
"log"
"time"
"github.com/YOU/bank/pkg/proto/credit"
"google.golang.org/grpc"
)
func main() {
log.Println("Client running ...")
conn, err := grpc.Dial(":50051", grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalln(err)
}
defer conn.Close()
client := credit.NewCreditServiceClient(conn)
request := &credit.CreditRequest{Amount: 1990.01}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
response, err := client.Credit(ctx, request)
if err != nil {
log.Fatalln(err)
}
log.Println("Response:", response.GetConfirmation())
}
package main
import (
"context"
"fmt"
"log"
"net"
"github.com/YOU/bank/pkg/proto/credit"
"google.golang.org/grpc"
)
type server struct {
credit.UnimplementedCreditServiceServer
}
func main() {
log.Println("Server running ...")
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalln(err)
}
srv := grpc.NewServer()
credit.RegisterCreditServiceServer(srv, &server{})
log.Fatalln(srv.Serve(lis))
}
func (s *server) Credit(ctx context.Context, request *credit.CreditRequest) (*credit.CreditResponse, error) {
log.Println(fmt.Sprintf("Request: %g", request.GetAmount()))
return &credit.CreditResponse{Confirmation: fmt.Sprintf("Credited %g", request.GetAmount())}, nil
}
$ make server
go build -race -ldflags "-s -w" -o bin/server server/main.go
bin/server
2020/04/04 18:07:37 Server running ...
$ make client
go build -race -ldflags "-s -w" -o bin/client client/main.go
bin/client
2020/04/04 18:07:42 Client running ...
2020/04/04 18:07:42 Response: Credited 1990.01
When you run client code above, the server will also output message below.
2020/04/04 18:07:42 Request: 1990.01