Skip to content

Commit

Permalink
Add read-only support to protoc-gen-swagger output (grpc-ecosystem#882)
Browse files Browse the repository at this point in the history
Can be set via:
* explicit swagger option on the field
* Implicit comment "Output only." on the field
  • Loading branch information
hypnoce authored and johanbrandhorst committed Mar 1, 2019
1 parent 0c2b3b1 commit 144843a
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 132 deletions.
8 changes: 8 additions & 0 deletions protoc-gen-swagger/genswagger/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject,

// Warning: Make sure not to overwrite any fields already set on the schema type.
schema.ExternalDocs = protoSchema.ExternalDocs
schema.ReadOnly = protoSchema.ReadOnly
schema.MultipleOf = protoSchema.MultipleOf
schema.Maximum = protoSchema.Maximum
schema.ExclusiveMaximum = protoSchema.ExclusiveMaximum
Expand Down Expand Up @@ -1223,6 +1224,12 @@ func updateSwaggerDataFromComments(swaggerObject interface{}, comment string, is
// Figure out which properties to update.
summaryValue := infoObjectValue.FieldByName("Summary")
descriptionValue := infoObjectValue.FieldByName("Description")
readOnlyValue := infoObjectValue.FieldByName("ReadOnly")

if readOnlyValue.Kind() == reflect.Bool && readOnlyValue.CanSet() && strings.Contains(comment, "Output only.") {
readOnlyValue.Set(reflect.ValueOf(true))
}

usingTitle := false
if !summaryValue.CanSet() {
summaryValue = infoObjectValue.FieldByName("Title")
Expand Down Expand Up @@ -1539,6 +1546,7 @@ func protoJSONSchemaToSwaggerSchemaCore(j *swagger_options.JSONSchema, reg *desc
func updateSwaggerObjectFromJSONSchema(s *swaggerSchemaObject, j *swagger_options.JSONSchema) {
s.Title = j.GetTitle()
s.Description = j.GetDescription()
s.ReadOnly = j.GetReadOnly()
s.MultipleOf = j.GetMultipleOf()
s.Maximum = j.GetMaximum()
s.ExclusiveMaximum = j.GetExclusiveMaximum()
Expand Down
135 changes: 135 additions & 0 deletions protoc-gen-swagger/genswagger/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package genswagger

import (
"encoding/json"
"errors"
"fmt"
"reflect"
"testing"
Expand Down Expand Up @@ -1274,6 +1275,7 @@ func TestRenderMessagesAsDefinition(t *testing.T) {
MaxProperties: 33,
MinProperties: 22,
Required: []string{"req"},
ReadOnly: true,
},
},
},
Expand All @@ -1298,6 +1300,7 @@ func TestRenderMessagesAsDefinition(t *testing.T) {
MaxProperties: 33,
MinProperties: 22,
Required: []string{"req"},
ReadOnly: true,
},
},
},
Expand Down Expand Up @@ -1498,3 +1501,135 @@ func TestProtoComments(t *testing.T) {
}
}
}

func TestUpdateSwaggerDataFromComments(t *testing.T) {

tests := []struct {
descr string
swaggerObject interface{}
comments string
expectedError error
expectedSwaggerObject interface{}
}{
{
descr: "empty comments",
swaggerObject: nil,
expectedSwaggerObject: nil,
comments: "",
expectedError: nil,
},
{
descr: "set field to read only",
swaggerObject: &swaggerSchemaObject{},
expectedSwaggerObject: &swaggerSchemaObject{
ReadOnly: true,
Description: "... Output only. ...",
},
comments: "... Output only. ...",
expectedError: nil,
},
{
descr: "set title",
swaggerObject: &swaggerSchemaObject{},
expectedSwaggerObject: &swaggerSchemaObject{
Title: "Comment with no trailing dot",
},
comments: "Comment with no trailing dot",
expectedError: nil,
},
{
descr: "set description",
swaggerObject: &swaggerSchemaObject{},
expectedSwaggerObject: &swaggerSchemaObject{
Description: "Comment with trailing dot.",
},
comments: "Comment with trailing dot.",
expectedError: nil,
},
{
descr: "use info object",
swaggerObject: &swaggerObject{
Info: swaggerInfoObject{
},
},
expectedSwaggerObject: &swaggerObject{
Info: swaggerInfoObject{
Description: "Comment with trailing dot.",
},
},
comments: "Comment with trailing dot.",
expectedError: nil,
},
{
descr: "multi line comment with title",
swaggerObject: &swaggerSchemaObject{},
expectedSwaggerObject: &swaggerSchemaObject {
Title: "First line",
Description: "Second line",
},
comments: "First line\n\nSecond line",
expectedError: nil,
},
{
descr: "multi line comment no title",
swaggerObject: &swaggerSchemaObject{},
expectedSwaggerObject: &swaggerSchemaObject {
Description: "First line.\n\nSecond line",
},
comments: "First line.\n\nSecond line",
expectedError: nil,
},
{
descr: "multi line comment with summary with dot",
swaggerObject: &swaggerOperationObject{},
expectedSwaggerObject: &swaggerOperationObject {
Summary: "First line.",
Description: "Second line",
},
comments: "First line.\n\nSecond line",
expectedError: nil,
},
{
descr: "multi line comment with summary no dot",
swaggerObject: &swaggerOperationObject{},
expectedSwaggerObject: &swaggerOperationObject {
Summary: "First line",
Description: "Second line",
},
comments: "First line\n\nSecond line",
expectedError: nil,
},
{
descr: "multi line comment with summary no dot",
swaggerObject: &schemaCore{},
expectedSwaggerObject: &schemaCore{},
comments: "Any comment",
expectedError: errors.New("no description nor summary property"),
},
}

for _, test := range tests {
t.Run(test.descr, func(t *testing.T) {
err := updateSwaggerDataFromComments(test.swaggerObject, test.comments, false)

if test.expectedError == nil {
if err != nil {
t.Errorf("unexpected error '%v'", err)
}
if !reflect.DeepEqual(test.swaggerObject, test.expectedSwaggerObject) {
t.Errorf("swaggerObject was not updated corretly, expected '%+v', got '%+v'", test.expectedSwaggerObject, test.swaggerObject)
}
} else {
if err == nil {
t.Error("expected update error not returned")
}
if !reflect.DeepEqual(test.swaggerObject, test.expectedSwaggerObject) {
t.Errorf("swaggerObject was not updated corretly, expected '%+v', got '%+v'", test.expectedSwaggerObject, test.swaggerObject)
}
if err.Error() != test.expectedError.Error() {
t.Errorf("expected error malformed, expected %q, got %q", test.expectedError.Error(), err.Error())
}
}
})
}
}
1 change: 1 addition & 0 deletions protoc-gen-swagger/genswagger/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ type swaggerSchemaObject struct {

ExternalDocs *swaggerExternalDocumentationObject `json:"externalDocs,omitempty"`

ReadOnly bool `json:"readOnly,omitempty"`
MultipleOf float64 `json:"multipleOf,omitempty"`
Maximum float64 `json:"maximum,omitempty"`
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
Expand Down
Loading

0 comments on commit 144843a

Please sign in to comment.