Skip to content

Commit

Permalink
grpc-ecosystem#1109 Inline streamingDefinitions in generated swagger …
Browse files Browse the repository at this point in the history
…to better support codegen tools (grpc-ecosystem#1112)

* grpc-ecosystem#1109 Inline streamingDefinitions in generated swagger

* Updated generated swagger streaming examples
  • Loading branch information
seanlaff authored and johanbrandhorst committed Jan 18, 2020
1 parent e8db07a commit 0c6cfab
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 93 deletions.
48 changes: 20 additions & 28 deletions examples/proto/examplepb/stream.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@
"200": {
"description": "A successful response.(streaming responses)",
"schema": {
"$ref": "#/x-stream-definitions/examplepbABitOfEverything"
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/examplepbABitOfEverything"
},
"error": {
"$ref": "#/definitions/runtimeStreamError"
}
},
"title": "Stream result of examplepbABitOfEverything"
}
}
},
Expand Down Expand Up @@ -61,7 +70,16 @@
"200": {
"description": "A successful response.(streaming responses)",
"schema": {
"$ref": "#/x-stream-definitions/subStringMessage"
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/subStringMessage"
},
"error": {
"$ref": "#/definitions/runtimeStreamError"
}
},
"title": "Stream result of subStringMessage"
}
}
},
Expand Down Expand Up @@ -374,31 +392,5 @@
}
}
}
},
"x-stream-definitions": {
"examplepbABitOfEverything": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/examplepbABitOfEverything"
},
"error": {
"$ref": "#/definitions/runtimeStreamError"
}
},
"title": "Stream result of examplepbABitOfEverything"
},
"subStringMessage": {
"type": "object",
"properties": {
"result": {
"$ref": "#/definitions/subStringMessage"
},
"error": {
"$ref": "#/definitions/runtimeStreamError"
}
},
"title": "Stream result of subStringMessage"
}
}
}
3 changes: 0 additions & 3 deletions protoc-gen-swagger/genswagger/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ func mergeTargetFile(targets []*wrapper, mergeFileName string) *wrapper {
for k, v := range f.swagger.Definitions {
mergedTarget.swagger.Definitions[k] = v
}
for k, v := range f.swagger.StreamDefinitions {
mergedTarget.swagger.StreamDefinitions[k] = v
}
for k, v := range f.swagger.Paths {
mergedTarget.swagger.Paths[k] = v
}
Expand Down
70 changes: 25 additions & 45 deletions protoc-gen-swagger/genswagger/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,42 +352,6 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject,
}
}

func renderMessagesAsStreamDefinition(messages messageMap, d swaggerDefinitionsObject, reg *descriptor.Registry) {
for name, msg := range messages {
if skipRenderingRef(name) {
continue
}

if opt := msg.GetOptions(); opt != nil && opt.MapEntry != nil && *opt.MapEntry {
continue
}
d[fullyQualifiedNameToSwaggerName(msg.FQMN(), reg)] = swaggerSchemaObject{
schemaCore: schemaCore{
Type: "object",
},
Title: fmt.Sprintf("Stream result of %s", fullyQualifiedNameToSwaggerName(msg.FQMN(), reg)),
Properties: &swaggerSchemaObjectProperties{
keyVal{
Key: "result",
Value: swaggerSchemaObject{
schemaCore: schemaCore{
Ref: fmt.Sprintf("#/definitions/%s", fullyQualifiedNameToSwaggerName(msg.FQMN(), reg)),
},
},
},
keyVal{
Key: "error",
Value: swaggerSchemaObject{
schemaCore: schemaCore{
Ref: fmt.Sprintf("#/definitions/%s", fullyQualifiedNameToSwaggerName(".grpc.gateway.runtime.StreamError", reg)),
},
},
},
},
}
}
}

// schemaOfField returns a swagger Schema Object for a protobuf field.
func schemaOfField(f *descriptor.Field, reg *descriptor.Registry, refs refMap) swaggerSchemaObject {
const (
Expand Down Expand Up @@ -877,8 +841,26 @@ func renderServices(services []*descriptor.Service, paths swaggerPathsObject, re
}
if meth.GetServerStreaming() {
desc += "(streaming responses)"
// Use the streamdefinition which wraps the message in a "result"
responseSchema.Ref = strings.Replace(responseSchema.Ref, `#/definitions/`, `#/x-stream-definitions/`, 1)
responseSchema.Type = "object"
responseSchema.Title = fmt.Sprintf("Stream result of %s", fullyQualifiedNameToSwaggerName(meth.ResponseType.FQMN(), reg))
responseSchema.Properties = &swaggerSchemaObjectProperties{
keyVal{
Key: "result",
Value: swaggerSchemaObject{
schemaCore: schemaCore{
Ref: responseSchema.Ref,
},
},
},
keyVal{
Key: "error",
Value: swaggerSchemaObject{
schemaCore: schemaCore{
Ref: fmt.Sprintf("#/definitions/%s", fullyQualifiedNameToSwaggerName(".grpc.gateway.runtime.StreamError", reg))},
},
},
}
responseSchema.Ref = ""
}

tag := svc.GetName()
Expand Down Expand Up @@ -1020,12 +1002,11 @@ func applyTemplate(p param) (*swaggerObject, error) {
// defined off of.
s := swaggerObject{
// Swagger 2.0 is the version of this document
Swagger: "2.0",
Consumes: []string{"application/json"},
Produces: []string{"application/json"},
Paths: make(swaggerPathsObject),
Definitions: make(swaggerDefinitionsObject),
StreamDefinitions: make(swaggerDefinitionsObject),
Swagger: "2.0",
Consumes: []string{"application/json"},
Produces: []string{"application/json"},
Paths: make(swaggerPathsObject),
Definitions: make(swaggerDefinitionsObject),
Info: swaggerInfoObject{
Title: *p.File.Name,
Version: "version not set",
Expand All @@ -1047,7 +1028,6 @@ func applyTemplate(p param) (*swaggerObject, error) {
e := enumMap{}
findServicesMessagesAndEnumerations(p.Services, p.reg, m, ms, e, requestResponseRefs)
renderMessagesAsDefinition(m, s.Definitions, p.reg, customRefs)
renderMessagesAsStreamDefinition(ms, s.StreamDefinitions, p.reg)
renderEnumerationsAsDefinition(e, s.Definitions, p.reg)

// File itself might have some comments and metadata.
Expand Down
24 changes: 8 additions & 16 deletions protoc-gen-swagger/genswagger/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -892,15 +892,17 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) {
if want, got, name := 3, len(result.Definitions), "len(Definitions)"; !reflect.DeepEqual(got, want) {
t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
}
// stream ExampleMessage must be present
if want, got, name := 1, len(result.StreamDefinitions), "len(StreamDefinitions)"; !reflect.DeepEqual(got, want) {
t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
if _, ok := result.Paths["/v1/echo"].Post.Responses["200"]; !ok {
t.Errorf("applyTemplate(%#v).%s = expected 200 response to be defined", file, `result.Paths["/v1/echo"].Post.Responses["200"]`)
} else {
streamExampleExampleMessage := result.StreamDefinitions["exampleExampleMessage"]
if want, got, name := "object", streamExampleExampleMessage.Type, `StreamDefinitions["exampleExampleMessage"].Type`; !reflect.DeepEqual(got, want) {
if want, got, name := "A successful response.(streaming responses)", result.Paths["/v1/echo"].Post.Responses["200"].Description, `result.Paths["/v1/echo"].Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) {
t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
}
streamExampleExampleMessage := result.Paths["/v1/echo"].Post.Responses["200"].Schema
if want, got, name := "object", streamExampleExampleMessage.Type, `result.Paths["/v1/echo"].Post.Responses["200"].Schema.Type`; !reflect.DeepEqual(got, want) {
t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
}
if want, got, name := "Stream result of exampleExampleMessage", streamExampleExampleMessage.Title, `StreamDefinitions["exampleExampleMessage"].Title`; !reflect.DeepEqual(got, want) {
if want, got, name := "Stream result of exampleExampleMessage", streamExampleExampleMessage.Title, `result.Paths["/v1/echo"].Post.Responses["200"].Schema.Title`; !reflect.DeepEqual(got, want) {
t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
}
streamExampleExampleMessageProperties := *(streamExampleExampleMessage.Properties)
Expand All @@ -925,16 +927,6 @@ func TestApplyTemplateRequestWithClientStreaming(t *testing.T) {
}
}
}
if want, got, name := 1, len(result.Paths["/v1/echo"].Post.Responses), "len(Paths[/v1/echo].Post.Responses)"; !reflect.DeepEqual(got, want) {
t.Errorf("applyTemplate(%#v).%s = %d want to be %d", file, name, got, want)
} else {
if want, got, name := "A successful response.(streaming responses)", result.Paths["/v1/echo"].Post.Responses["200"].Description, `result.Paths["/v1/echo"].Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) {
t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
}
if want, got, name := "#/x-stream-definitions/exampleExampleMessage", result.Paths["/v1/echo"].Post.Responses["200"].Schema.Ref, `result.Paths["/v1/echo"].Post.Responses["200"].Description`; !reflect.DeepEqual(got, want) {
t.Errorf("applyTemplate(%#v).%s = %s want to be %s", file, name, got, want)
}
}

// If there was a failure, print out the input and the json result for debugging.
if t.Failed() {
Expand Down
1 change: 0 additions & 1 deletion protoc-gen-swagger/genswagger/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ type swaggerObject struct {
Produces []string `json:"produces"`
Paths swaggerPathsObject `json:"paths"`
Definitions swaggerDefinitionsObject `json:"definitions"`
StreamDefinitions swaggerDefinitionsObject `json:"x-stream-definitions,omitempty"`
SecurityDefinitions swaggerSecurityDefinitionsObject `json:"securityDefinitions,omitempty"`
Security []swaggerSecurityRequirementObject `json:"security,omitempty"`
ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"`
Expand Down

0 comments on commit 0c6cfab

Please sign in to comment.