12/08/2018, 14:52

A simple API using protobuf and gRPC

This tutorial provides a basic Go programmer’s introduction to working with gRPC. Define a service in a .proto file. Generate server and client code using the protocol buffer compiler. Use the Go gRPC API to write a simple client and server for your service. This requires Go 1.6 or ...

This tutorial provides a basic Go programmer’s introduction to working with gRPC.

  • Define a service in a .proto file.
  • Generate server and client code using the protocol buffer compiler.
  • Use the Go gRPC API to write a simple client and server for your service.

This requires Go 1.6 or later, ProtocolBuffers 3.0.0 or later

// Ubuntu 16.04
$sudo apt install libprotobuf-dev

Requires that GOPATH is set

$ go help gopath
$ # ensure the PATH contains $GOPATH/bin
$ export PATH=$PATH:$GOPATH/bin
for fish guy!!!
set -gx PATH $PATH $GOPATH/bin

Then, go get -u as usual.

go get google.golang.org/grpc
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway

Make sure that your GOPATH/binisinyourGOPATH/bin is in your GOPATH/binisinyourPATH.

a. Define your service in gRPC

pb/service.proto:

syntax = "proto3";
option go_package = "echo";
 
// Echo Service
//
// Echo Service API consists of a single service which returns a message.
package echo;
 
import "google/api/annotations.proto";
 
// Message represents a simple message sent to the Echo service.
message Message {
    // Id represents the message identifier.
    string id = 1;
    // The message to be sent.
    string msg = 2;
}
 
// Echo service responds to incoming echo requests.
service EchoService {
    // Echo method receives a simple message and returns it.
    // The message posted as the id parameter will also be returned.
    rpc Echo(Message) returns (Message) {
        option (google.api.http) = {
            post: "/v1/example/echo/{id}/{msg}"
        };
    }
}

b. Gnerate gRPC stub

Generating client and server code

$ protoc -I/usr/local/include -I. 
  -I$GOPATH/src 
 -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis 
 --go_out=Mgoogle/api/annotations.proto=github.com/gengo/grpc-gateway/third_party/googleapis/google/api,plugins=grpc:. 
  pb/service.proto

Generate reverse-proxy for your RESTful API

$ 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:. 
   pb/service.proto

c. Write your Server code

server/server.go:

package main
 
import (
    "flag"
 
    "github.com/golang/glog"
    pb "github.com/go-grpc-tutorial/pb"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "net"
)
 
// Implements of EchoServiceServer
 
type echoServer struct{}
 
func newEchoServer() pb.EchoServiceServer {
    return new(echoServer)
}
 
func (s *echoServer) Echo(ctx context.Context, msg *pb.Message) (*pb.Message, error) {
    glog.Info(msg)
    return msg, nil
}
 
func Run() error {
    listen, err := net.Listen("tcp", ":50051")
    if err != nil {
        return err
    }
    server := grpc.NewServer()
    pb.RegisterEchoServiceServer(server, newEchoServer())
    server.Serve(listen)
    return nil
}
 
func main() {
    flag.Parse()
    defer glog.Flush()
 
    if err := Run(); err != nil {
        glog.Fatal(err)
    }
}

server/server-rproxy.go: (REST JSON API)

package main
 
import (
    "flag"
    "net/http"
    "github.com/grpc-ecosystem/grpc-gateway/runtime"
    "github.com/golang/glog"
    pb "github.com/go-grpc-tutorial/pb"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
)
 
var (
    echoEndpoint = flag.String("echo_endpoint", "localhost:50051", "endpoint of EchoService")
)
 
func RunEndPoint(address string, opts ...runtime.ServeMuxOption) error {
    ctx := context.Background()
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()
 
    mux := runtime.NewServeMux(opts...)
    dialOpts := []grpc.DialOption{grpc.WithInsecure()}
    err := pb.RegisterEchoServiceHandlerFromEndpoint(ctx, mux, *echoEndpoint, dialOpts)
    if err != nil {
        return err
    }
 
    http.ListenAndServe(address, mux)
    return nil
}
 
func main() {
    flag.Parse()
    defer glog.Flush()
 
    if err := RunEndPoint(":8080"); err != nil {
        glog.Fatal(err)
    }
}

d. Client Side

server/client.go:

package main
 
import (
    "log"
    "os"
 
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    pb "github.com/go-grpc-tutorial/pb"
)
 
const (
    address = "localhost:50051"
    defaultName = "PhuongDV"
)
 
func main() {
    // Set up a connection to the server.
    conn, err := grpc.Dial(address, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewEchoServiceClient(conn)
 
    // Contact the server and print out its response.
    name := defaultName
    if len(os.Args) > 1 {
        name = os.Args[1]
    }
    r, err := c.Echo(context.Background(), &pb.Message{Id: "1", Msg: name})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.Msg)
}

e. Try it out!

To compile and run the server, assuming you are in the folder $$OPATH/src/github.com/go-grpc-tutorial, simply:

$ go run server/server.go

Likewise, to run the client:

$ go run client/client.go
 
017/03/06 17:36:33 Greeting: PhuongDV

Call REST API

$ curl -X POST "http://localhost:8080/v1/example/echo/1/PhuongDV"
 
{"id":"1","msg":"PhuongD"}

Copy by @ https://pdoviet.wordpress.com/2017/03/06/a-simple-api-using-protobuf-and-grpc/

0