I'm going to write a customer service that is running by using gRPC and then create a client to talk with the service
First, create a Go module and write a proto file
mkdir grpc-api
cd grpc-api
mkdir protos
touch protos/customer.proto
syntax = "proto3";
package customerpb;
option go_package="server/customerpb";
message CustomerInfo {
string customer_id = 1;
string customer_name = 2;
}
message GetCustomersRequest {}
message GetCustomersResponse {
repeated CustomerInfo customers = 1;
}
message GetCustomerByIdRequest {
string customer_id = 1;
}
message GetCustomerByIdResponse {
CustomerInfo customer = 1;
}
service Customer {
rpc GetCustomers(GetCustomersRequest) returns (GetCustomersResponse) {};
rpc GetCustomerById(GetCustomerByIdRequest) returns (GetCustomerByIdResponse) {};
}
Then create the client module and the customer service module
mkdir client && cd client
go mod init grpc-api/client
cd ..
mkdir customer && cd customer
go mod init grpc-api/customer
cd ..
go work init ./client
go work use ./customer
Now install protoc
to work with .proto file
sudo apt install -y protobuf-compiler
Install Go plugin for the protoc and generate Go files for gRPC server/client
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
export PATH="$PATH:$(go env GOPATH)/bin"
And generate the Go gRPC files
protoc --go_out=./client --go-grpc_out=./client protos/customer.proto
protoc --go_out=./customer --go-grpc_out=./customer protos/customer.proto
Then implement the customer service
touch customer/server/server.go
package server
import (
"context"
"grpc-api/customer/server/customerpb"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type Customer struct {
ID string
Name string
}
var _customers = []Customer{{ID: "A310", Name: "There"}, {ID: "K423", Name: "Kian"}}
type CustomerServer struct {
customerpb.UnimplementedCustomerServer
}
func (CustomerServer) GetCustomers(ctx context.Context, in *customerpb.GetCustomersRequest) (*customerpb.GetCustomersResponse, error) {
res := &customerpb.GetCustomersResponse{}
for _, customer := range _customers {
res.Customers = append(res.Customers, &customerpb.CustomerInfo{
CustomerId: customer.ID,
CustomerName: customer.Name,
})
}
return res, nil
}
func (CustomerServer) GetCustomerById(ctx context.Context, in *customerpb.GetCustomerByIdRequest) (*customerpb.GetCustomerByIdResponse, error) {
for _, customer := range _customers {
if customer.ID == in.CustomerId {
return &customerpb.GetCustomerByIdResponse{
Customer: &customerpb.CustomerInfo{
CustomerId: customer.ID,
CustomerName: customer.Name,
},
}, nil
}
}
return nil, status.Errorf(codes.NotFound, "the customer does not exist")
}
Next, write the main.go
file for the server
touch customer/main.go
package main
import (
"context"
"grpc-api/customer/server"
"grpc-api/customer/server/customerpb"
"log"
"net"
"os/signal"
"syscall"
"google.golang.org/grpc"
)
func main() {
lis, err := net.Listen("tcp", ":9090")
if err != nil {
log.Fatalln(err)
}
srv := grpc.NewServer()
customerpb.RegisterCustomerServer(srv, &server.CustomerServer{})
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
go func() {
<-ctx.Done()
stop()
log.Println("Server is exiting")
srv.Stop()
}()
log.Println("Server is running...")
if err := srv.Serve(lis); err != nil && err != grpc.ErrServerStopped {
log.Fatalf("Error while serving: %v", err)
}
log.Println("Server is closed")
}
Then write the client
touch client/main.go
package main
import (
"context"
"grpc-api/client/server/customerpb"
"log"
"google.golang.org/grpc"
)
func main() {
conn, err := grpc.Dial(":9090", grpc.WithInsecure())
if err != nil {
log.Fatal(err)
}
res, err := customerpb.NewCustomerClient(conn).GetCustomers(
context.Background(),
&customerpb.GetCustomersRequest{},
)
if err != nil {
log.Fatal(err)
}
log.Println(res.Customers)
if len(res.Customers) > 0 {
res, err := customerpb.NewCustomerClient(conn).GetCustomerById(
context.Background(),
&customerpb.GetCustomerByIdRequest{
CustomerId: res.Customers[0].CustomerId,
},
)
if err != nil {
log.Fatal(err)
}
log.Println(res.Customer.CustomerName)
}
}
Ok~ now you can start the apps
For the server, run this
go run grpc-api/customer
And for the client, use this
go run grpc-api/client
Finally, gRPC services are working
sources