The advantages of grpc are no longer described, but how to provide Restful interface to the outside world and how to use grpc-gateway to convert grpc to Restful API when there is no desire to develop the same function repeatedly.
install
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway go get -u github.com/micro/protobuf/{proto,protoc-gen-go}
If it is only used, it is very simple to add the import file and http configuration statement to the original grpc. proto file.
import file
import "google/api/annotations.proto";
http configuration statement
service Bookinfo { // get book information rpc Getall (GetallRequest) returns (GetallResponse) { option (google.api.http) = { post: "/bookinfo/getall" body: "*" }; }; }
Probably explain
bookinfo.proto file
syntax = "proto3"; package bookinfo; import "google/api/annotations.proto"; option go_package = "bookinfopb"; // The book service makes it possible to get or set book's detail information service Bookinfo { // get book information rpc Getall (GetallRequest) returns (GetallResponse) { option (google.api.http) = { post: "/bookinfo/getall" body: "*" }; }; // add books information rpc Add (AddRequest) returns (AddResponse){ option (google.api.http) = { post: "/bookinfo/add" body: "*" }; }; } message GetallRequest { // ID of user string userid = 1; } message GetallResponse { // Book info list repeated BookInfo bookinfolist = 1; } message BookInfo { // Name of book string book_name = 1; // Author string author = 2; // Chapters name repeated ChapterInfo chapters_info = 3; } message ChapterInfo { // Chapter number sint32 chapter_num = 1; // Chapter name string chapter_name = 2; // Words cound sint32 words_count = 3; } message AddRequest { // Books information repeated BookInfo books_info = 1; } message AddResponse { repeated sint32 field = 1; }
Define the request interface name, parameters, and return results
The parameter of the Getall interface is the userid of string type. The return result is an array of BookInfo (identified by repeated)
Generating stub files for grpc services
protoc -I/usr/local/include -I. \ -I$(GOPATH)/src \ -I$(GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \ --go_out=plugins=grpc:. bookinfo-srv/proto/bookinfo/bookinfo.proto
Generate bookinfo.pb.go file
Generating stub files for grpc-gateway
protoc -I/usr/local/include -I. \
-I $(GOPATH)/src \
-I $(GOPATH)/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
--grpc-gateway_out=logtostderr=true:. bookinfo-srv/proto/bookinfo/bookinfo.proto
Generate bookinfo.pb.gw.go file
Implementation of grpc function
-
service.go
package main
import (
pb "grpcT1/bookinfo-srv/proto/bookinfo" bkinfoprocess "grpcT1/bookinfo-srv/process" "net" "log" "google.golang.org/grpc"
)
const (PORT = ":50051"
)
func main() {
listener, err := net.Listen("tcp", PORT) if err != nil { log.Fatalf("failed to listen: %v", err) } log.Printf("listen on: %s\n", PORT) server := grpc.NewServer() pb.RegisterBookinfoServer(server, bkinfoprocess.NewBookinfo()) if err := server.Serve(listener); err != nil { log.Fatalf("failed to serve: %v", err) }
}
RegisterBookinfoServer method is defined and implemented in bookinfo.pb.go
-
Specific Logical Implementation of Interface Method Defined by process/bookinfo.go
package bookinfoprocess
import (
bookinfo "grpcT1/bookinfo-srv/proto/bookinfo" "context" "fmt"
)
type bookinfosrvc struct {}
func NewBookinfo() bookinfo.BookinfoServer {
return &bookinfosrvc{}
}
func (s bookinfosrvc) Getall(ctx context.Context, p bookinfo.GetallRequest) (*bookinfo.GetallResponse, error) {
res := &bookinfo.GetallResponse{} fmt.Println("bookinfo.getall") cpsInfo := make([]*bookinfo.ChapterInfo,4) cpsInfo[0] = &bookinfo.ChapterInfo{ChapterNum:1, ChapterName:"Preface", WordsCount:3259} cpsInfo[1] = &bookinfo.ChapterInfo{ChapterNum:2, ChapterName:"Boer", WordsCount:4559} cpsInfo[2] = &bookinfo.ChapterInfo{ChapterNum:3, ChapterName:"character", WordsCount:7559} cpsInfo[3] = &bookinfo.ChapterInfo{ChapterNum:4, ChapterName:"function", WordsCount:7859} bkInfo := &bookinfo.BookInfo{BookName:"Ugly language", Author:"Bill", ChaptersInfo:cpsInfo} res.Bookinfolist = append(res.Bookinfolist, bkInfo) return res, nil
}
func (s bookinfosrvc) Add(ctx context.Context, p bookinfo.AddRequest) (*bookinfo.AddResponse, error) {
return nil, nil
}
gateway provides http interface to the outside world
-
gateway/main.go
package main
import (
"flag" "net/http" "github.com/golang/glog" "golang.org/x/net/context" "github.com/grpc-ecosystem/grpc-gateway/runtime" "google.golang.org/grpc" gw "grpcT1/bookinfo-srv/proto/bookinfo"
)
var (
echoEndpoint = flag.String("getall_endpoint", "rpcserver:50051", "endpoint of BookInfoService")
)
func run() error {
ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() mux := runtime.NewServeMux() opts := []grpc.DialOption{grpc.WithInsecure()} err := gw.RegisterBookinfoHandlerFromEndpoint(ctx, mux, *echoEndpoint, 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) }
}
The RegisterBookinfoHandlerFromEndpoint method is defined and implemented in bookinfo.pb.gw.go
grpc request
-
client/main.go
package main
import (
pb "grpcT1/bookinfo-srv/proto/bookinfo" "google.golang.org/grpc" "log" "context"
)
const (
ADDRESS = "rpcserver:50051"
)
func main() {
// Connect to gRPC server conn, err := grpc.Dial(ADDRESS, grpc.WithInsecure()) if err != nil { log.Fatalf("connect error: %v", err) } defer conn.Close() // Initialize gRPC client client := pb.NewBookinfoClient(conn) resp, err := client.Getall(context.Background(), &pb.GetallRequest{Userid:"tt"}) if err != nil { log.Fatalf("Getall error: %v", err) } length := len(resp.Bookinfolist) for i:=0;i<length;i++ { log.Printf("bookName:%s\n",resp.Bookinfolist[i].BookName) log.Printf("author:%s\n", resp.Bookinfolist[i].Author) chaptersCount := len(resp.Bookinfolist[i].ChaptersInfo) for j:=0;j<chaptersCount;j++ { log.Printf("---Chapter.Num:%d\n", resp.Bookinfolist[i].ChaptersInfo[j].ChapterNum) log.Printf("---Chapter.Name:%s\n", resp.Bookinfolist[i].ChaptersInfo[j].ChapterName) log.Printf("---Chapter.WordsCount:%d\n", resp.Bookinfolist[i].ChaptersInfo[j].WordsCount) log.Println("") } }
}
client calls the implementation of grpc interface. Definition and Implementation of NewBookinfoClient Method in bookinfo.pb.go
http request test
curl -X POST -k http://localhost:8080/bookinfo/getall -d '{"userid":"tt"}'
Detailed code can be obtained from this https://github.com/BinWang-sh...
makefile in the root directory generates stub and docker images
Docker directory has docker-compose file execution docker-compose up can run directly