Skip to content

Commit

Permalink
Apply additional Swagger properties using JSON.
Browse files Browse the repository at this point in the history
Depends on PR grpc-ecosystem#134. Reverts 562956f.
  • Loading branch information
ivucica committed Feb 10, 2017
1 parent 6863684 commit a9c77a3
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 3 deletions.
46 changes: 46 additions & 0 deletions examples/examplepb/echo_service.pb.go

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

37 changes: 37 additions & 0 deletions examples/examplepb/echo_service.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,39 @@ option go_package = "examplepb";
//
// Echo Service API consists of a single service which returns
// a message.
//
// <!-- swagger extras start
// {
// "info": {
// "title": "Echo Service",
// "version": "1.0",
// "contact": {
// "name": "gRPC-Gateway project",
// "url": "https://github.com/grpc-ecosystem/grpc-gateway",
// "email": "[email protected]"
// }
// },
// "host": "localhost",
// "externalDocs": {
// "url": "https://github.com/grpc-ecosystem/grpc-gateway",
// "description": "More about gRPC-Gateway"
// }
// }
// swagger extras end -->
package grpc.gateway.examples.examplepb;

import "google/api/annotations.proto";

// SimpleMessage represents a simple message sent to the Echo service.
//
// <!-- swagger extras start
// {
// "externalDocs": {
// "url": "http://github.com/grpc-ecosystem/grpc-gateway",
// "description": "Find out more about EchoService"
// }
// }
// swagger extras end -->
message SimpleMessage {
// Id represents the message identifier.
string id = 1;
Expand All @@ -21,6 +49,15 @@ service EchoService {
//
// The message posted as the id parameter will also be
// returned.
//
// <!-- swagger extras start
// {
// "externalDocs": {
// "url": "http://github.com/grpc-ecosystem/grpc-gateway",
// "description": "Find out more about EchoService"
// }
// }
// swagger extras end -->
rpc Echo(SimpleMessage) returns (SimpleMessage) {
option (google.api.http) = {
post: "/v1/example/echo/{id}"
Expand Down
14 changes: 12 additions & 2 deletions examples/examplepb/echo_service.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
"info": {
"title": "Echo Service",
"description": "Echo Service API consists of a single service which returns\na message.",
"version": "version not set"
"version": "1.0",
"contact": {
"name": "gRPC-Gateway project",
"url": "https://github.com/gengo/grpc-gateway",
"email": "[email protected]"
}
},
"host": "localhost",
"schemes": [
"http",
"https"
Expand Down Expand Up @@ -39,7 +45,11 @@
],
"tags": [
"EchoService"
]
],
"externalDocs": {
"description": "Find out more about EchoService",
"url": "http://github.com/gengo/grpc-gateway"
}
}
},
"/v1/example/echo_body": {
Expand Down
39 changes: 38 additions & 1 deletion protoc-gen-swagger/genswagger/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor"
)

var swaggerExtrasRegexp = regexp.MustCompile(`(?s)^(.*[^\s])[\s]*<!-- swagger extras start(.*)swagger extras end -->[\s]*(.*)$`)

func listEnumNames(enum *descriptor.Enum) (names []string) {
for _, value := range enum.GetValue() {
names = append(names, value.GetName())
Expand Down Expand Up @@ -606,20 +608,55 @@ func applyTemplate(p param) (string, error) {
// updateSwaggerDataFromComments updates a Swagger object based on a comment
// from the proto file.
//
// As a first step, a section matching:
//
// <!-- swagger extras start.*swagger extras end-->
//
// where .* contains valid JSON will be stored for later processing, and then
// removed from the passed string.
// (Implementation note: Currently, the JSON gets immediately applied and
// thus cannot override summary and description.)
//
// First paragraph of a comment is used for summary. Remaining paragraphs of a
// comment are used for description. If 'Summary' field is not present on the
// passed swaggerObject, the summary and description are joined by \n\n.
//
// If there is a field named 'Info', its 'Summary' and 'Description' fields
// will be updated instead.
// will be updated instead. (JSON always gets applied directly to the passed
// object.)
//
// If there is no 'Summary', the same behavior will be attempted on 'Title',
// but only if the last character is not a period.
//
// To apply additional Swagger properties, one can pass valid JSON as described
// before. This JSON gets parsed and applied to the passed swaggerObject
// directly. This lets users easily apply custom properties such as contact
// details, API base path, et al.
func updateSwaggerDataFromComments(swaggerObject interface{}, comment string) error {
if len(comment) == 0 {
return nil
}

// Find a section containing additional Swagger metadata.
matches := swaggerExtrasRegexp.FindStringSubmatch(comment)

if len(matches) > 0 {
// If found, before further processing, replace the
// comment with a version that does not contain the
// extras.
comment = matches[1]
if len(matches[3]) > 0 {
comment += "\n\n" + matches[3]
}

// Parse the JSON and apply it.
// TODO(ivucica): apply extras /after/ applying summary
// and description.
if err := json.Unmarshal([]byte(matches[2]), swaggerObject); err != nil {
return fmt.Errorf("error: %s, parsing: %s", err.Error(), matches[2])
}
}

// Figure out what to apply changes to.
swaggerObjectValue := reflect.ValueOf(swaggerObject)
infoObjectValue := swaggerObjectValue.Elem().FieldByName("Info")
Expand Down

0 comments on commit a9c77a3

Please sign in to comment.