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;
}
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 makes sense), so I usually will write *.pb.go
in file .gitignore
More info:
Top comments (7)
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:
Any thoughts on this peculiarity?
Not sure what happened on your computer, could you provide a sample for reproducing?
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.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.
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
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.
maybe last option helpful for me. okay i will try it. thanks for suggest me :)