Skip to content

Commit

Permalink
improve WKT handling in gateway and openapi output
Browse files Browse the repository at this point in the history
  • Loading branch information
tmc authored and achew22 committed Dec 5, 2017
1 parent e4b8a93 commit 04d5a1e
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 7 deletions.
7 changes: 6 additions & 1 deletion protoc-gen-grpc-gateway/descriptor/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,12 @@ func (r *Registry) newParam(meth *Method, path string) (Parameter, error) {
target := fields[l-1].Target
switch target.GetType() {
case descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_GROUP:
return Parameter{}, fmt.Errorf("aggregate type %s in parameter of %s.%s: %s", target.Type, meth.Service.GetName(), meth.GetName(), path)
glog.V(2).Infoln("found aggregate type:", target, target.TypeName)
if IsWellKnownType(*target.TypeName) {
glog.V(2).Infoln("found well known aggregate type:", target)
} else {
return Parameter{}, fmt.Errorf("aggregate type %s in parameter of %s.%s: %s", target.Type, meth.Service.GetName(), meth.GetName(), path)
}
}
return Parameter{
FieldPath: FieldPath(fields),
Expand Down
14 changes: 14 additions & 0 deletions protoc-gen-grpc-gateway/descriptor/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import (
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule"
)

// IsWellKnownType returns true if the provided fully qualified type name is considered 'well-known'.
func IsWellKnownType(typeName string) bool {
_, ok := wellKnownTypeConv[typeName]
return ok
}

// GoPackage represents a golang package
type GoPackage struct {
// Path is the package path to the package.
Expand Down Expand Up @@ -194,6 +200,9 @@ func (p Parameter) ConvertFuncExpr() (string, error) {
}
typ := p.Target.GetType()
conv, ok := tbl[typ]
if !ok {
conv, ok = wellKnownTypeConv[p.Target.GetTypeName()]
}
if !ok {
return "", fmt.Errorf("unsupported field type %s of parameter %s in %s.%s", typ, p.FieldPath, p.Method.Service.GetName(), p.Method.GetName())
}
Expand Down Expand Up @@ -319,4 +328,9 @@ var (
descriptor.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32P",
descriptor.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64P",
}

wellKnownTypeConv = map[string]string{
".google.protobuf.Timestamp": "runtime.Timestamp",
".google.protobuf.Duration": "runtime.Duration",
}
)
27 changes: 21 additions & 6 deletions protoc-gen-swagger/genswagger/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ import (
swagger_options "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options"
)

var wktSchemas = map[string]schemaCore{
".google.protobuf.Timestamp": schemaCore{
Type: "string",
Format: "date-time",
},
".google.protobuf.Duration": schemaCore{
Type: "string",
},
}

func listEnumNames(enum *descriptor.Enum) (names []string) {
for _, value := range enum.GetValue() {
names = append(names, value.GetName())
Expand Down Expand Up @@ -165,6 +175,8 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject,
switch name {
case ".google.protobuf.Timestamp":
continue
case ".google.protobuf.Duration":
continue
}
if opt := msg.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry {
continue
Expand Down Expand Up @@ -236,11 +248,8 @@ func schemaOfField(f *descriptor.Field, reg *descriptor.Registry) swaggerSchemaO

switch ft := fd.GetType(); ft {
case pbdescriptor.FieldDescriptorProto_TYPE_ENUM, pbdescriptor.FieldDescriptorProto_TYPE_MESSAGE, pbdescriptor.FieldDescriptorProto_TYPE_GROUP:
if fd.GetTypeName() == ".google.protobuf.Timestamp" && pbdescriptor.FieldDescriptorProto_TYPE_MESSAGE == ft {
core = schemaCore{
Type: "string",
Format: "date-time",
}
if wktSchema, ok := wktSchemas[fd.GetTypeName()]; ok {
core = wktSchema
} else {
core = schemaCore{
Ref: "#/definitions/" + fullyQualifiedNameToSwaggerName(fd.GetTypeName(), reg),
Expand Down Expand Up @@ -481,7 +490,13 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re
var paramType, paramFormat string
switch pt := parameter.Target.GetType(); pt {
case pbdescriptor.FieldDescriptorProto_TYPE_GROUP, pbdescriptor.FieldDescriptorProto_TYPE_MESSAGE:
return fmt.Errorf("only primitive types are allowed in path parameters")
if descriptor.IsWellKnownType(parameter.Target.GetTypeName()) {
schema := schemaOfField(parameter.Target, reg)
paramType = schema.Type
paramFormat = schema.Format
} else {
return fmt.Errorf("only primitive and well-known types are allowed in path parameters")
}
case pbdescriptor.FieldDescriptorProto_TYPE_ENUM:
paramType = fullyQualifiedNameToSwaggerName(parameter.Target.GetTypeName(), reg)
paramFormat = ""
Expand Down
18 changes: 18 additions & 0 deletions runtime/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package runtime

import (
"strconv"

"github.com/gogo/protobuf/jsonpb"
"github.com/golang/protobuf/ptypes/duration"
"github.com/golang/protobuf/ptypes/timestamp"
)

// String just returns the given string.
Expand Down Expand Up @@ -56,3 +60,17 @@ func Uint32(val string) (uint32, error) {
}
return uint32(i), nil
}

// Timestamp converts the given RFC3339 formatted string into a timestamp.Timestamp.
func Timestamp(val string) (*timestamp.Timestamp, error) {
var r *timestamp.Timestamp
err := jsonpb.UnmarshalString(val, r)
return r, err
}

// Duration converts the given string into a timestamp.Duration.
func Duration(val string) (*duration.Duration, error) {
var r *duration.Duration
err := jsonpb.UnmarshalString(val, r)
return r, err
}

0 comments on commit 04d5a1e

Please sign in to comment.