UP | HOME

gRPC quick start in Go

What is RPC? RPC means "remote procedure call". The concept is call remote function as local function.

Then gRPC? It is a framework that help you create RPC.

Traditional RPC has some problem make it hard to use. For example, how do you know, what type of message you get?

Usually, we use JSON or others format. But marshal & unmarshal quickly became a big issue. Because as time goes on, we don't actually know which service use which field, thus we can't reduce anything.

And server & client will get more further more far for same reason.

These all, won't be an issue in gRPC.

In gRPC, you define a *.proto file for your service.

At here, we will create one named UserService

syntax = "proto3";

package user;

service UserService {
  rpc GetUser (Empty) returns (User) {}
}

// define message type
message Empty {}
message User {
  string name = 1;
  int32 age = 2;
}

To generate code, I usually use go generate ./...

So let's have a file gen.go, just leave a comment about what command you want to execute.

//go:generate sh -c "protoc -I./user --go_out=plugins=grpc:./user ./user/*.proto"

Implement service:

import "path/to/grpc_generated/user"

type UserService struct{}

func (us *UserService) GetUser(ctx context.Context, u *user.Empty) (*user.User, error) {
    return &user.UserName{
	Name: "Danny",
	Age:  21,
    }, nil
}

Create server:

import (
    "net"
    "path/to/grpc_generated/user"
    "google.golang.org/grpc"
)

func main() {
    l, err := net.Listen("tcp", ":50051")
    // handle err
    server := grpc.NewServer()

    service := user.UserServiceServer(&UserService{})
    user.RegisterUserServiceServer(server, service)

    err = server.Serve(l)
    // handle err
}

Final is our client:

import (
    "fmt"
    "net"
    "path/to/grpc_generated/user"
    "google.golang.org/grpc"
)

func main() {
    conn, err := grpc.Dial("localhost:50051", grpc.WithInsercure())
    // handle err
    defer conn.Close()
    client := user.NewUserServiceClient(conn)
    u, err := client.GetUser(context.Background(), &user.Empty{})
    // handle err
    fmt.Printf("Name: %s, Age: %d", u.Name, u.Age)
}

After that, run go generate ./... from project root dir.

Then go run server.go, open another terminal, go run client.go

I usually won't commit generated code(unless commit it is make sense), so I usually will write *.pb.go in file .gitignore

More info:

Date: 2018-08-16 Thu 00:00

Author: Lîm Tsú-thuàn