Skip to content

Commit

Permalink
Make grpc-gateway support enum fields in path parameter; repeated enu…
Browse files Browse the repository at this point in the history
…m fields are also supported.
  • Loading branch information
linuxerwang committed Nov 29, 2016
1 parent 199c40a commit 71e188e
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 26 deletions.
45 changes: 23 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,26 @@ go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -u github.com/grpc-ecosystem/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`.

1. Define your service in gRPC

your_service.proto:
```protobuf
syntax = "proto3";
package example;
message StringMessage {
string value = 1;
}
service YourService {
rpc Echo(StringMessage) returns (StringMessage) {}
}
```
2. Add a [custom option](https://cloud.google.com/service-management/reference/rpc/google.api#http) to the .proto file

your_service.proto:
```diff
syntax = "proto3";
Expand All @@ -73,7 +73,7 @@ Make sure that your `$GOPATH/bin` is in your `$PATH`.
message StringMessage {
string value = 1;
}

service YourService {
- rpc Echo(StringMessage) returns (StringMessage) {}
+ rpc Echo(StringMessage) returns (StringMessage) {
Expand All @@ -85,27 +85,27 @@ Make sure that your `$GOPATH/bin` is in your `$PATH`.
}
```
3. Generate gRPC stub

```sh
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/grpc-ecosystem/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`.
4. Implement your service in gRPC as usual
1. (Optional) Generate gRPC stub in the language you want.

e.g.
```sh
protoc -I/usr/local/include -I. \
-I$GOPATH/src \
-I$GOPATH/src/github.com/grpc-ecosystem/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/grpc-ecosystem/grpc-gateway/third_party/googleapis \
Expand All @@ -115,57 +115,57 @@ Make sure that your `$GOPATH/bin` is in your `$PATH`.
```
2. Implement your service
5. Generate reverse-proxy

```sh
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:. \
path/to/your_service.proto
```

It will generate a reverse proxy `path/to/your_service.pb.gw.go`.
6. Write an entrypoint

Now you need to write an entrypoint of the proxy server.
```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 "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)
}
Expand Down Expand Up @@ -204,14 +204,15 @@ To use the same port for custom HTTP handlers (e.g. serving `swagger.json`), gRP
* Method parameters in request body
* Method parameters in request path
* Method parameters in query string
* Enum fields in path parameter (including repeated enum fields).
* Mapping streaming APIs to newline-delimited JSON streams
* Mapping HTTP headers with `Grpc-Metadata-` prefix to gRPC metadata
* Optionally emitting API definition for [Swagger](http://swagger.io).
* Setting [gRPC timeouts](http://www.grpc.io/docs/guides/wire.html) through inbound HTTP `Grpc-Timeout` header.

### Want to support
But not yet.
* bytes and enum fields in path parameter. #5
* bytes fields in path parameter. #5
* Optionally generating the entrypoint. #8
* `import_path` parameter

Expand All @@ -227,7 +228,7 @@ But patch is welcome.
* [How gRPC error codes map to HTTP status codes in the response](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/runtime/errors.go#L15)
* HTTP request source IP is added as `X-Forwarded-For` gRPC request header
* HTTP request host is added as `X-Forwarded-Host` gRPC request header
* HTTP `Authorization` header is added as `authorization` gRPC request header
* HTTP `Authorization` header is added as `authorization` gRPC request header
* Remaining HTTP header keys are prefixed with `Grpc-Metadata-` and added with their values to gRPC request header
* While configurable, the default {un,}marshaling uses [jsonpb](https://godoc.org/github.com/golang/protobuf/jsonpb) with `OrigName: true`.

Expand Down
8 changes: 4 additions & 4 deletions runtime/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values []
case reflect.Ptr:
if f.IsNil() {
m = reflect.New(f.Type().Elem())
f.Set(m)
f.Set(m.Convert(f.Type()))
}
m = f.Elem()
continue
Expand Down Expand Up @@ -101,13 +101,13 @@ func populateRepeatedField(f reflect.Value, values []string) error {
if !ok {
return fmt.Errorf("unsupported field type %s", elemType)
}
f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)))
f.Set(reflect.MakeSlice(f.Type(), len(values), len(values)).Convert(f.Type()))
for i, v := range values {
result := conv.Call([]reflect.Value{reflect.ValueOf(v)})
if err := result[1].Interface(); err != nil {
return err.(error)
}
f.Index(i).Set(result[0])
f.Index(i).Set(result[0].Convert(f.Index(i).Type()))
}
return nil
}
Expand All @@ -121,7 +121,7 @@ func populateField(f reflect.Value, value string) error {
if err := result[1].Interface(); err != nil {
return err.(error)
}
f.Set(result[0])
f.Set(result[0].Convert(f.Type()))
return nil
}

Expand Down

0 comments on commit 71e188e

Please sign in to comment.