Skip to content

Commit

Permalink
Fix: path item objects become block scalars [#3557] (#3566)
Browse files Browse the repository at this point in the history
* fix

* implement toYAMLNode

* add comment

* check len

* add test

* add comment

* rename

* update

* generate
  • Loading branch information
qawatake authored Sep 9, 2023
1 parent 042abde commit d476e2a
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 4 deletions.
1 change: 1 addition & 0 deletions protoc-gen-openapiv2/internal/genopenapi/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ go_test(
"template_test.go",
"types_test.go",
],
data = glob(["testdata/**"]),
embed = [":genopenapi"],
deps = [
"//internal/descriptor",
Expand Down
33 changes: 29 additions & 4 deletions protoc-gen-openapiv2/internal/genopenapi/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,20 +150,45 @@ func (po openapiPathsObject) MarshalYAML() (interface{}, error) {
pathObjectNode.Kind = yaml.MappingNode

for _, pathData := range po {
var pathNode, pathItemObjectNode yaml.Node
var pathNode yaml.Node

pathNode.SetString(pathData.Path)
b, err := yaml.Marshal(pathData.PathItemObject)
pathItemObjectNode, err := pathData.PathItemObject.toYAMLNode()
if err != nil {
return nil, err
}
pathItemObjectNode.SetString(string(b))
pathObjectNode.Content = append(pathObjectNode.Content, &pathNode, &pathItemObjectNode)
pathObjectNode.Content = append(pathObjectNode.Content, &pathNode, pathItemObjectNode)
}

return pathObjectNode, nil
}

// We can simplify this implementation once the go-yaml bug is resolved. See: https://github.com/go-yaml/yaml/issues/643.
//
// func (pio *openapiPathItemObject) toYAMLNode() (*yaml.Node, error) {
// var node yaml.Node
// if err := node.Encode(pio); err != nil {
// return nil, err
// }
// return &node, nil
// }
func (pio *openapiPathItemObject) toYAMLNode() (*yaml.Node, error) {
var doc yaml.Node
var buf bytes.Buffer
ec := yaml.NewEncoder(&buf)
ec.SetIndent(2)
if err := ec.Encode(pio); err != nil {
return nil, err
}
if err := yaml.Unmarshal(buf.Bytes(), &doc); err != nil {
return nil, err
}
if len(doc.Content) == 0 {
return nil, errors.New("unexpected number of yaml nodes")
}
return doc.Content[0], nil
}

func (so openapiInfoObject) MarshalJSON() ([]byte, error) {
type alias openapiInfoObject
return extensionMarshalJSON(alias(so), so.extensions)
Expand Down
50 changes: 50 additions & 0 deletions protoc-gen-openapiv2/internal/genopenapi/generator_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package genopenapi_test

import (
"os"
"reflect"
"sort"
"strings"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/grpc-ecosystem/grpc-gateway/v2/internal/descriptor"
"github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/internal/genopenapi"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -120,6 +122,54 @@ func TestGenerateExtension(t *testing.T) {
}
}

func TestGenerateYAML(t *testing.T) {
t.Parallel()

tests := []struct {
name string
inputProtoText string
wantYAML string
}{
{
// It tests https://github.com/grpc-ecosystem/grpc-gateway/issues/3557.
name: "path item object",
inputProtoText: "testdata/generator/path_item_object.prototext",
wantYAML: "testdata/generator/path_item_object.swagger.yaml",
},
}

for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

b, err := os.ReadFile(tt.inputProtoText)
if err != nil {
t.Fatal(err)
}
var req pluginpb.CodeGeneratorRequest
if err := prototext.Unmarshal(b, &req); err != nil {
t.Fatal(err)
}

resp := requireGenerate(t, &req, genopenapi.FormatYAML, false, true)
if len(resp) != 1 {
t.Fatalf("invalid count, expected: 1, actual: %d", len(resp))
}
got := resp[0].GetContent()

want, err := os.ReadFile(tt.wantYAML)
if err != nil {
t.Fatal(err)
}
diff := cmp.Diff(string(want), got)
if diff != "" {
t.Fatalf("content not match\n%s", diff)
}
})
}
}

func requireGenerate(
tb testing.TB,
req *pluginpb.CodeGeneratorRequest,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
file_to_generate: "your/service/v1/your_service.proto"
proto_file: {
name: "your/service/v1/your_service.proto"
package: "your.service.v1"
message_type: {
name: "StringMessage"
field: {
name: "value"
number: 1
label: LABEL_OPTIONAL
type: TYPE_STRING
json_name: "value"
}
}
service: {
name: "YourService"
method: {
name: "Echo"
input_type: ".your.service.v1.StringMessage"
output_type: ".your.service.v1.StringMessage"
options: {
[google.api.http]: {
post: "/api/echo"
}
}
}
}
options: {
go_package: "github.com/yourorg/yourprotos/gen/go/your/service/v1"
}
syntax: "proto3"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
swagger: "2.0"
info:
title: your/service/v1/your_service.proto
version: version not set
tags:
- name: YourService
consumes:
- application/json
produces:
- application/json
paths:
/api/echo:
post:
operationId: YourService_Echo
responses:
"200":
description: A successful response.
schema:
$ref: '#/definitions/StringMessage'
parameters:
- name: value
in: query
required: false
type: string
tags:
- YourService
definitions:
StringMessage:
type: object
properties:
value:
type: string

0 comments on commit d476e2a

Please sign in to comment.