grpc-gateway
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.
Background
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.
Installation
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
Usage
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
Parameters and flags
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
More examples are available under examples
directory.
examplepb/echo_service.proto
, examplepb/a_bit_of_everything.proto
: service definition
examplepb/echo_service.pb.go
, examplepb/a_bit_of_everything.pb.go
: [generated] stub of the service
examplepb/echo_service.pb.gw.go
, examplepb/a_bit_of_everything.pb.gw.go
: [generated] reverse proxy for the service
server/main.go
: service implementation
main.go
: entrypoint of the generated reverse proxy
Features
Supported
- 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.
Want to support
But not yet.
- bytes and enum fields in path parameter. #5
- Optionally generating the entrypoint. #8
import_path
parameter
No plan to support
But patch is welcome.
- Method parameters in HTTP headers
- Handling trailer metadata
- Encoding request/response body in XML
- True bi-directional streaming. (Probably impossible?)
License
grpc-gateway is licensed under the BSD 3-Clause License.
See LICENSE.txt for more details.