grpc-gateway is a plugin of protoc. It reads gRPC service definition, and generates a reverse-proxy server which translates a RESTful JSON API into gRPC.
It helps you to provide your APIs in both gRPC and RESTful style at the same time.
gRPC is great -- it generates API clients and server stubs in many programming languages, it is fast, easy-to-use, bandwidth-efficient and its design is combat-proven by Google. However, you might still want to provide classic RESTful APIs too for some reasons -- compatibility with languages not supported by gRPC, API backward-compatibility or aesthetics of RESTful architecture.
That's what grpc-gateway helps you to do. You just need to implement your gRPC service with a small amount of custom options. Then the reverse-proxy generated by grpc-gateway serves RESTful API on top of the gRPC service.
First you need to install ProtocolBuffers 3.0.0-beta-3 or later.
mkdir tmp
cd tmp
git clone https://github.com/google/protobuf
cd protobuf
./autogen.sh
./configure
make
make check
sudo make install
Then, go get -u
as usual.
go get -u github.com/gengo/grpc-gateway/protoc-gen-grpc-gateway
go get -u github.com/gengo/grpc-gateway/protoc-gen-swagger
go get -u github.com/golang/protobuf/protoc-gen-go
Make sure that your $GOPATH/bin
is in your $PATH
.
-
Define your service in gRPC
your_service.proto:
syntax = "proto3"; package example; message StringMessage { string value = 1; } service YourService { rpc Echo(StringMessage) returns (StringMessage) {} }
-
Add a custom option to the .proto file
your_service.proto:
syntax = "proto3"; package example; + +import "google/api/annotations.proto"; + message StringMessage { string value = 1; } service YourService { - rpc Echo(StringMessage) returns (StringMessage) {} + rpc Echo(StringMessage) returns (StringMessage) { + option (google.api.http) = { + post: "/v1/example/echo" + body: "*" + }; + } }
-
Generate gRPC stub
protoc -I/usr/local/include -I. \ -I$GOPATH/src \ -I$GOPATH/src/github.com/gengo/grpc-gateway/third_party/googleapis \ --go_out=Mgoogle/api/annotations.proto=github.com/gengo/grpc-gateway/third_party/googleapis/google/api,plugins=grpc:. \ path/to/your_service.proto
It will generate a stub file
path/to/your_service.pb.go
. -
Implement your service in gRPC as usual
- (Optional) Generate gRPC stub in the language you want.
e.g.
protoc -I/usr/local/include -I. \ -I$GOPATH/src \ -I$GOPATH/src/github.com/gengo/grpc-gateway/third_party/googleapis \ --ruby_out=. \ path/to/your/service_proto protoc -I/usr/local/include -I. \ -I$GOPATH/src \ -I$GOPATH/src/github.com/gengo/grpc-gateway/third_party/googleapis \ --plugin=protoc-gen-grpc-ruby=grpc_ruby_plugin \ --grpc-ruby_out=. \ path/to/your/service.proto
- Implement your service
-
Generate reverse-proxy
protoc -I/usr/local/include -I. \ -I$GOPATH/src \ -I$GOPATH/src/github.com/gengo/grpc-gateway/third_party/googleapis \ --grpc-gateway_out=logtostderr=true:. \ path/to/your_service.proto
It will generate a reverse proxy
path/to/your_service.pb.gw.go
. -
Write an entrypoint
Now you need to write an entrypoint of the proxy server.
package main import ( "flag" "net/http" "github.com/golang/glog" "golang.org/x/net/context" "github.com/gengo/grpc-gateway/runtime" "google.golang.org/grpc" gw "path/to/your_service_package" ) var ( echoEndpoint = flag.String("echo_endpoint", "localhost:9090", "endpoint of YourService") ) func run() error { ctx := context.Background() ctx, cancel := context.WithCancel(ctx) defer cancel() mux := runtime.NewServeMux() opts := []grpc.DialOption{grpc.WithInsecure()} err := gw.RegisterYourServiceHandlerFromEndpoint(ctx, mux, *echoEndpoint, opts) if err != nil { return err } http.ListenAndServe(":8080", mux) return nil } func main() { flag.Parse() defer glog.Flush() if err := run(); err != nil { glog.Fatal(err) } }
-
(Optional) Generate swagger definitions
protoc -I/usr/local/include -I. \ -I$GOPATH/src \ -I$GOPATH/src/github.com/gengo/grpc-gateway/third_party/googleapis \ --swagger_out=logtostderr=true:. \ path/to/your_service.proto
protoc-gen-grpc-gateway
supports custom mapping from Protobuf import
to Golang import path.
They are compatible to the parameters with same names in protoc-gen-go
.
protoc-gen-grpc-gateway
also supports some more command line flags to control logging. You can give these flags together with parameters above. Run protoc-gen-grpc-gateway --help
for more details about the flags.
More examples are available under examples
directory.
examplepb/echo_service.proto
,examplepb/a_bit_of_everything.proto
: service definitionexamplepb/echo_service.pb.go
,examplepb/a_bit_of_everything.pb.go
: [generated] stub of the serviceexamplepb/echo_service.pb.gw.go
,examplepb/a_bit_of_everything.pb.gw.go
: [generated] reverse proxy for the service
server/main.go
: service implementationmain.go
: entrypoint of the generated reverse proxy
- Generating JSON API handlers
- Method parameters in request body
- Method parameters in request path
- Method parameters in query string
- Mapping streaming APIs to JSON streams
- Mapping HTTP headers with
Grpc-Metadata-
prefix to gRPC metadata - Optionally emitting API definition for Swagger.
- Setting gRPC timeouts through inbound HTTP
Grpc-Timeout
header.
But not yet.
- bytes and enum fields in path parameter. #5
- Optionally generating the entrypoint. #8
import_path
parameter
But patch is welcome.
- Method parameters in HTTP headers
- Handling trailer metadata
- Encoding request/response body in XML
- True bi-directional streaming. (Probably impossible?)
grpc-gateway is licensed under the BSD 3-Clause License. See LICENSE.txt for more details.