Aug 27, 2019
3 mins read
A easy-to-use tool to specify the API across multiple language.
Just define the request/response fields once in a .proto file, and the proto-gen-xxx will take care of the language-specified part, generates the code for you.
repeated for arraymessage Foo {
repeated string name_list = 1;
}
optional as its name, optionalmessage Foo {
optional string name = 1;
}
reserved formessage Foo {
reserved 2, 15, 9 to 11;
reserved "foo", "bar";
}
enum EnumAllowingAlias {
option allow_alias = true;
UNKNOWN = 0;
STARTED = 1;
RUNNING = 1;
}
ExampleType example = 1import "google/protobuf/any.proto";go get -u google.golang.org/grpcgo get -u github.com/golang/protobuf/protoc-gen-goprotoc --go_out=plugins=grpc:. *.protoFirst you will define the interface of API. The conventions of naming are:
MessageTypefield_nameExample: use ID to search a person.
search.proto
syntax = "proto3";
message SearchRequest {
int32 query = 1;
}
message SearchResponse {
string name = 1;
}
service Searcher {
rpc Search(SearchRequest) returns (SearchResponse){}
}
You need to actually implements the function that defines in the search.proto file.
server.gotype Service struct {
}
func (s *Service) Search(ctx context.Context, req *pb.SearchRequest) (*pb.SearchResponse, error) {
query := req.Query
fmt.Println("query id is: ", query)
return &pb.SearchResponse{
Name: data[query],
}, nil
}
func main() {
listenPort, err := net.Listen("tcp", ":5000")
if err != nil {
log.Fatalln(err)
}
server := grpc.NewServer()
service := &Service{}
// format: Register{service_name}Server
pb.RegisterSearcherServer(server, service)
server.Serve(listenPort)
}
client.gofunc main() {
conn, err := grpc.Dial("127.0.0.1:5000", grpc.WithInsecure())
if err != nil {
log.Fatal("client connection error:", err)
}
defer conn.Close()
// format: New{service_name}Client
client := pb.NewSearcherClient(conn)
message := &pb.SearchRequest{
Query: 1,
}
res, err := client.Search(context.TODO(), message)
fmt.Printf("result:%#v \n", res)
fmt.Printf("error::%#v \n", err)
}
grpc-gateway (Optional)If the client wants to access the server via RESTful HTTP, a grpc-gateway is needed to translate the traffic into gRPC for you.
grpc-gateway is quite handy that you will just need to do little configuration than the gateway can be generated along with the other generated code at the same time.
search.proto
syntax = "proto3";
# add
import "google/api/annotations.proto";
message SearchRequest{
int32 query = 1;
}
message SearchResponse{
string name = 1;
}
service Searcher{
# modified
rpc Search(SearchRequest) returns (SearchResponse){
option (google.api.http) = {
post: "/api/query"
body: "*"
};
}
}
gateway.go
import (
"flag"
"context"
"net/http"
"google.golang.org/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/golang/glog"
gw "../pb"
)
var (
endPoint = flag.String("port", "localhost:5000", "endpoint")
)
func run() error {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := gw.RegisterSearcherHandlerFromEndpoint(ctx, mux, *endPoint, opts)
if err != nil {
return err
}
return http.ListenAndServe(":8080", mux)
}
func main() {
flag.Parse()
defer glog.Flush()
if err := run(); err != nil {
glog.Fatal(err)
}
}
Sharing is caring!