Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add openapiv2_json_name field option to specify non alphanumeric characters in JSON property name #686

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion examples/clients/abe/a_bit_of_everything_service_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,9 +539,10 @@ func (a ABitOfEverythingServiceApi) GetMessageWithBody(id string, body Examplepb
* @param nonConventionalNameValue
* @param timestampValue
* @param repeatedEnumValue repeated enum value. it is comma-separated in query. - ZERO: ZERO means 0 - ONE: ONE means 1
* @param id
* @return *ProtobufEmpty
*/
func (a ABitOfEverythingServiceApi) GetQuery(uuid string, singleNestedName string, singleNestedAmount int64, singleNestedOk string, floatValue float32, doubleValue float64, int64Value string, uint64Value string, int32Value int32, fixed64Value string, fixed32Value int64, boolValue bool, stringValue string, bytesValue string, uint32Value int64, enumValue string, sfixed32Value int32, sfixed64Value string, sint32Value int32, sint64Value string, repeatedStringValue []string, oneofString string, nonConventionalNameValue string, timestampValue time.Time, repeatedEnumValue []string) (*ProtobufEmpty, *APIResponse, error) {
func (a ABitOfEverythingServiceApi) GetQuery(uuid string, singleNestedName string, singleNestedAmount int64, singleNestedOk string, floatValue float32, doubleValue float64, int64Value string, uint64Value string, int32Value int32, fixed64Value string, fixed32Value int64, boolValue bool, stringValue string, bytesValue string, uint32Value int64, enumValue string, sfixed32Value int32, sfixed64Value string, sint32Value int32, sint64Value string, repeatedStringValue []string, oneofString string, nonConventionalNameValue string, timestampValue time.Time, repeatedEnumValue []string, id bool) (*ProtobufEmpty, *APIResponse, error) {

var localVarHttpMethod = strings.ToUpper("Get")
// create path and map variables
Expand Down Expand Up @@ -586,6 +587,7 @@ func (a ABitOfEverythingServiceApi) GetQuery(uuid string, singleNestedName strin
var repeatedEnumValueCollectionFormat = "csv"
localVarQueryParams.Add("repeated_enum_value", a.Configuration.APIClient.ParameterToString(repeatedEnumValue, repeatedEnumValueCollectionFormat))

localVarQueryParams.Add("@id", a.Configuration.APIClient.ParameterToString(id, ""))

// to determine the Content-Type header
localVarHttpContentTypes := []string{ "application/json", "application/x-foo-mime", }
Expand Down
2 changes: 2 additions & 0 deletions examples/clients/abe/examplepb_a_bit_of_everything.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,6 @@ type ExamplepbABitOfEverything struct {
TimestampValue time.Time `json:"timestamp_value,omitempty"`

RepeatedEnumValue []ExamplepbNumericEnum `json:"repeated_enum_value,omitempty"`

Id bool `json:"@id,omitempty"`
}
304 changes: 157 additions & 147 deletions examples/proto/examplepb/a_bit_of_everything.pb.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions examples/proto/examplepb/a_bit_of_everything.proto
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ message ABitOfEverything {

// repeated enum value. it is comma-separated in query
repeated NumericEnum repeated_enum_value = 28;

bool at_id = 30 [(grpc.gateway.protoc_gen_swagger.options.openapiv2_json_name) = "@id"];
}

message Body {
Expand Down
11 changes: 11 additions & 0 deletions examples/proto/examplepb/a_bit_of_everything.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,13 @@
"ONE"
]
}
},
{
"name": "@id",
"in": "query",
"required": false,
"type": "boolean",
"format": "boolean"
}
],
"tags": [
Expand Down Expand Up @@ -1113,6 +1120,10 @@
"$ref": "#/definitions/examplepbNumericEnum"
},
"title": "repeated enum value. it is comma-separated in query"
},
"@id": {
"type": "boolean",
"format": "boolean"
}
},
"description": "Intentionaly complicated message type to cover many features of Protobuf.",
Expand Down
35 changes: 32 additions & 3 deletions protoc-gen-swagger/genswagger/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,17 @@ func getEnumDefault(enum *descriptor.Enum) string {
return ""
}

func getFieldName(f *descriptor.Field) string {
fd := f.FieldDescriptorProto

n, err := extractJsonNameFromFieldDescriptor(fd)
if err != nil || n == "" {
return f.GetName()
}

return n
}

// messageToQueryParameters converts a message to a list of swagger query parameters.
func messageToQueryParameters(message *descriptor.Message, reg *descriptor.Registry, pathParams []descriptor.Parameter) (params []swaggerParameterObject, err error) {
for _, field := range message.Fields {
Expand Down Expand Up @@ -107,7 +118,7 @@ func queryParams(message *descriptor.Message, field *descriptor.Field, prefix st
desc = strings.TrimSpace(schema.Title + ". " + schema.Description)
}
param := swaggerParameterObject{
Name: prefix + field.GetName(),
Name: prefix + getFieldName(field),
Description: desc,
In: "query",
Type: schema.Type,
Expand Down Expand Up @@ -143,7 +154,7 @@ func queryParams(message *descriptor.Message, field *descriptor.Field, prefix st
return nil, fmt.Errorf("unknown message type %s", fieldType)
}
for _, nestedField := range msg.Fields {
p, err := queryParams(msg, nestedField, prefix+field.GetName()+".", reg, pathParams)
p, err := queryParams(msg, nestedField, prefix+getFieldName(field)+".", reg, pathParams)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -251,7 +262,7 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject,
panic(err)
}

schema.Properties = append(schema.Properties, keyVal{f.GetName(), fieldValue})
schema.Properties = append(schema.Properties, keyVal{getFieldName(f), fieldValue})
}
d[fullyQualifiedNameToSwaggerName(msg.FQMN(), reg)] = schema
}
Expand Down Expand Up @@ -1234,6 +1245,24 @@ func extractSwaggerOptionFromFileDescriptor(file *pbdescriptor.FileDescriptorPro
return opts, nil
}

func extractJsonNameFromFieldDescriptor(fd *pbdescriptor.FieldDescriptorProto) (string, error) {
if fd.Options == nil {
return "", nil
}
if !proto.HasExtension(fd.Options, swagger_options.E_Openapiv2JsonName) {
return "", nil
}
ext, err := proto.GetExtension(fd.Options, swagger_options.E_Openapiv2JsonName)
if err != nil {
return "", err
}
name, ok := ext.(*string)
if !ok {
return "", fmt.Errorf("extension is %T; want a string", ext)
}
return *name, nil
}

func swaggerSchemaFromProtoSchema(s *swagger_options.Schema, reg *descriptor.Registry, refs refMap) swaggerSchemaObject {
ret := swaggerSchemaObject{
ExternalDocs: protoExternalDocumentationToSwaggerExternalDocumentation(s.GetExternalDocs()),
Expand Down
58 changes: 35 additions & 23 deletions protoc-gen-swagger/options/annotations.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions protoc-gen-swagger/options/annotations.proto
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,10 @@ extend google.protobuf.ServiceOptions {
// different descriptor messages.
Tag openapiv2_tag = 1042;
}
extend google.protobuf.FieldOptions {
// ID assigned by protobuf-global-extension-registry@google.com for grpc-gateway project.
//
// All IDs are the same, as assigned. It is okay that they are the same, as they extend
// different descriptor messages.
string openapiv2_json_name = 1042;
}