DEV Community

林子篆
林子篆

Posted on • Originally published at dannypsnl.github.io on

gRPC quick start in Go

What is RPC? RPC means “remote procedure call”. The concept is called a remote function as a local function.

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

Traditional RPC has some problem making 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 further farther for the 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;
}
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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 makes sense), so I usually will write *.pb.go in file .gitignore

More info:

Top comments (7)

Collapse
 
ernsheong profile image
Jonathan ES Lin • Edited

What's interesting to me is that when I create the GRPC client in another package (outside main) and try to use it elsewhere... the GRPC calls fails with:

rpc error: code = Canceled desc = grpc: the client connection is closing

Any thoughts on this peculiarity?

Collapse
 
dannypsnl profile image
林子篆

Not sure what happened on your computer, could you provide a sample for reproducing?

Collapse
 
ernsheong profile image
Jonathan ES Lin

Thanks for the reply. I figured it out. Gotta be careful with defer conn.Close() if calling outside main function... After function ends it will close the connection and the client cannot be used anymore.

Thread Thread
 
dannypsnl profile image
林子篆

Good to hear that; yes, better to using context if you want to manage the lifecycle. It provides a not bad abstraction for stopping a goroutine.

Collapse
 
bimbimprasetyoafif profile image
Bimo Prasetyo Afif • Edited

Hey, i already have golang backend with rest api implemented. can i use grpc without make .proto file ? because i already have service, interface, repo, etc

Collapse
 
dannypsnl profile image
林子篆

A short answer is it's possible, but that also means you are using HTTP2 directly.
That would make the gRPC became useless. Or you have to implement client/server-side abstraction for RPC.
Therefore I guess you probably can use .proto, just redirect to existed services.

Collapse
 
bimbimprasetyoafif profile image
Bimo Prasetyo Afif

maybe last option helpful for me. okay i will try it. thanks for suggest me :)