Skip to content

Commit f4bbdef

Browse files
authored
Feat: add service option (#6)
1 parent 468231d commit f4bbdef

File tree

14 files changed

+404
-84
lines changed

14 files changed

+404
-84
lines changed

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@ pb_test:
1515

1616
install_gnostic:
1717
go install github.com/google/gnostic/cmd/[email protected]
18+
19+
protobuf:
20+
protobuild vendor
21+
protobuild gen
22+
rm -rf github.com

docs/_docs.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package docs
2+
3+
// https://github.com/kollalabs/protoc-gen-openapi/tree/main

examples/tests/openapiv3annotations/message.proto

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,37 @@ service Messaging1 {
9494
}
9595

9696
service Messaging2 {
97-
rpc UpdateMessage (Message) returns (Message) {}
97+
rpc UpdateMessage (Message) returns (Message) {
98+
option (openapi.v3.operation) = {
99+
tags: ["abc=def"],
100+
specification_extension: [
101+
{
102+
name: "x-operation-id";
103+
value: {
104+
yaml: "updateMessage"
105+
};
106+
}
107+
],
108+
parameters: [{
109+
parameter: {
110+
description: "jwt token",
111+
in: "header",
112+
name: "Authorization",
113+
required: true,
114+
},
115+
}],
116+
security: [
117+
{
118+
additional_properties: [
119+
{
120+
name: "BasicAuth";
121+
value: {}
122+
}
123+
]
124+
}
125+
]
126+
};
127+
}
98128
}
99129

100130
message Message {

examples/tests/rpctypes/message.openapi.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ paths:
1818
application/json:
1919
schema:
2020
$ref: '#/components/schemas/Status'
21+
x-folder: api/test
2122
components:
2223
schemas:
2324
GoogleProtobufAny:

examples/tests/rpctypes/message.proto

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,18 @@ package tests.rpctypes.message.v1;
2020
import "google/protobuf/empty.proto";
2121
import "google/api/annotations.proto";
2222
import "google/rpc/status.proto";
23+
import "openapiv3/service.proto";
2324

2425
option go_package = "github.com/google/gnostic/apps/protoc-gen-openapi/examples/tests/rpctypes/message/v1;message";
2526

2627
service Status {
28+
option(openapi.v3.service).specification_extension={
29+
name: "x-folder"
30+
value: {
31+
yaml: "api/test"
32+
}
33+
};
34+
2735
rpc GetStatus(google.protobuf.Empty) returns (google.rpc.Status) {
2836
option(google.api.http) = {
2937
get: "/v1/status"

generator/generator.go

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@ import (
2525

2626
v3 "github.com/google/gnostic-models/openapiv3"
2727
"google.golang.org/genproto/googleapis/api/annotations"
28-
status_pb "google.golang.org/genproto/googleapis/rpc/status"
28+
statuspb "google.golang.org/genproto/googleapis/rpc/status"
2929
"google.golang.org/protobuf/compiler/protogen"
3030
"google.golang.org/protobuf/proto"
3131
"google.golang.org/protobuf/reflect/protoreflect"
3232
"google.golang.org/protobuf/types/descriptorpb"
33-
any_pb "google.golang.org/protobuf/types/known/anypb"
33+
"google.golang.org/protobuf/types/known/anypb"
3434

35-
wk "github.com/pubgo/protoc-gen-openapi/generator/wellknown"
35+
"github.com/pubgo/protoc-gen-openapi/generator/wellknown"
3636
)
3737

3838
type Configuration struct {
@@ -55,8 +55,8 @@ const (
5555
// to know the message descriptors for google.rpc.Status as well
5656
// as google.protobuf.Any.
5757
var (
58-
statusProtoDesc = (&status_pb.Status{}).ProtoReflect().Descriptor()
59-
anyProtoDesc = (&any_pb.Any{}).ProtoReflect().Descriptor()
58+
statusProtoDesc = (&statuspb.Status{}).ProtoReflect().Descriptor()
59+
anyProtoDesc = (&anypb.Any{}).ProtoReflect().Descriptor()
6060
)
6161

6262
// OpenAPIv3Generator holds internal state needed to generate an OpenAPIv3 document for a transcoded Protocol Buffer service.
@@ -122,15 +122,17 @@ func (g *OpenAPIv3Generator) buildDocumentV3() *v3.Document {
122122
// track of which schemas are referenced in the response so we can
123123
// add them later.
124124
for _, file := range g.inputFiles {
125-
if file.Generate {
126-
// Merge any `Document` annotations with the current
127-
extDocument := proto.GetExtension(file.Desc.Options(), v3.E_Document)
128-
if extDocument != nil {
129-
proto.Merge(d, extDocument.(*v3.Document))
130-
}
125+
if !file.Generate {
126+
continue
127+
}
131128

132-
g.addPathsToDocumentV3(d, file.Services)
129+
// Merge any `Document` annotations with the current
130+
extDocument := proto.GetExtension(file.Desc.Options(), v3.E_Document)
131+
if extDocument != nil {
132+
proto.Merge(d, extDocument.(*v3.Document))
133133
}
134+
135+
g.addPathsToDocumentV3(d, file.Services)
134136
}
135137

136138
// While we have required schemas left to generate, go through the files again
@@ -579,11 +581,11 @@ func (g *OpenAPIv3Generator) buildOperationV3(
579581
// Add the default response if needed
580582
if *g.conf.DefaultResponse {
581583
anySchemaName := g.reflect.formatMessageName(anyProtoDesc)
582-
anySchema := wk.NewGoogleProtobufAnySchema(anySchemaName)
584+
anySchema := wellknown.NewGoogleProtobufAnySchema(anySchemaName)
583585
g.addSchemaToDocumentV3(d, anySchema)
584586

585587
statusSchemaName := g.reflect.formatMessageName(statusProtoDesc)
586-
statusSchema := wk.NewGoogleRpcStatusSchema(statusSchemaName, anySchemaName)
588+
statusSchema := wellknown.NewGoogleRpcStatusSchema(statusSchemaName, anySchemaName)
587589
g.addSchemaToDocumentV3(d, statusSchema)
588590

589591
defaultResponse := &v3.NamedResponseOrReference{
@@ -592,7 +594,7 @@ func (g *OpenAPIv3Generator) buildOperationV3(
592594
Oneof: &v3.ResponseOrReference_Response{
593595
Response: &v3.Response{
594596
Description: "Default error response",
595-
Content: wk.NewApplicationJsonMediaType(&v3.SchemaOrReference{
597+
Content: wellknown.NewApplicationJsonMediaType(&v3.SchemaOrReference{
596598
Oneof: &v3.SchemaOrReference_Reference{
597599
Reference: &v3.Reference{XRef: "#/components/schemas/" + statusSchemaName},
598600
},
@@ -705,8 +707,9 @@ func (g *OpenAPIv3Generator) addOperationToDocumentV3(d *v3.Document, op *v3.Ope
705707
// addPathsToDocumentV3 adds paths from a specified file descriptor.
706708
func (g *OpenAPIv3Generator) addPathsToDocumentV3(d *v3.Document, services []*protogen.Service) {
707709
for _, service := range services {
708-
annotationsCount := 0
710+
extService, _ := proto.GetExtension(service.Desc.Options(), E_Service).(*Service)
709711

712+
annotationsCount := 0
710713
for _, method := range service.Methods {
711714
comment := g.filterCommentString(method.Comments.Leading)
712715
inputMessage := method.Input
@@ -764,6 +767,18 @@ func (g *OpenAPIv3Generator) addPathsToDocumentV3(d *v3.Document, services []*pr
764767
proto.Merge(op, extOperation.(*v3.Operation))
765768
}
766769

770+
// Merge any `Service` annotations with the current
771+
if extService != nil {
772+
op.Parameters = append(op.Parameters, extService.Parameters...)
773+
op.SpecificationExtension = append(op.SpecificationExtension, extService.SpecificationExtension...)
774+
op.Tags = append(op.Tags, extService.Tags...)
775+
op.Servers = append(op.Servers, extService.Servers...)
776+
op.Security = append(op.Security, extService.Security...)
777+
if extService.ExternalDocs != nil {
778+
proto.Merge(op.ExternalDocs, extService.ExternalDocs)
779+
}
780+
}
781+
767782
for _, v := range op.Parameters {
768783
if v.Oneof == nil {
769784
continue
@@ -774,7 +789,7 @@ func (g *OpenAPIv3Generator) addPathsToDocumentV3(d *v3.Document, services []*pr
774789
p := v1.Parameter
775790
if p.In == "header" {
776791
if p.Schema == nil {
777-
p.Schema = wk.NewStringSchema()
792+
p.Schema = wellknown.NewStringSchema()
778793
}
779794
}
780795
}
@@ -840,15 +855,15 @@ func (g *OpenAPIv3Generator) addSchemasForMessagesToDocumentV3(d *v3.Document, m
840855
// `google.protobuf.Value` and `google.protobuf.Any` have special JSON transcoding
841856
// so we can't just reflect on the message descriptor.
842857
if typeName == ".google.protobuf.Value" {
843-
g.addSchemaToDocumentV3(d, wk.NewGoogleProtobufValueSchema(schemaName))
858+
g.addSchemaToDocumentV3(d, wellknown.NewGoogleProtobufValueSchema(schemaName))
844859
continue
845860
} else if typeName == ".google.protobuf.Any" {
846-
g.addSchemaToDocumentV3(d, wk.NewGoogleProtobufAnySchema(schemaName))
861+
g.addSchemaToDocumentV3(d, wellknown.NewGoogleProtobufAnySchema(schemaName))
847862
continue
848863
} else if typeName == ".google.rpc.Status" {
849864
anySchemaName := g.reflect.formatMessageName(anyProtoDesc)
850-
g.addSchemaToDocumentV3(d, wk.NewGoogleProtobufAnySchema(anySchemaName))
851-
g.addSchemaToDocumentV3(d, wk.NewGoogleRpcStatusSchema(schemaName, anySchemaName))
865+
g.addSchemaToDocumentV3(d, wellknown.NewGoogleProtobufAnySchema(anySchemaName))
866+
g.addSchemaToDocumentV3(d, wellknown.NewGoogleRpcStatusSchema(schemaName, anySchemaName))
852867
continue
853868
}
854869

generator/reflector.go

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
"google.golang.org/protobuf/compiler/protogen"
2424
"google.golang.org/protobuf/reflect/protoreflect"
2525

26-
wk "github.com/pubgo/protoc-gen-openapi/generator/wellknown"
26+
"github.com/pubgo/protoc-gen-openapi/generator/wellknown"
2727
)
2828

2929
const (
@@ -90,10 +90,10 @@ func (r *OpenAPIv3Reflector) responseContentForMessage(message protoreflect.Mess
9090
}
9191

9292
if typeName == ".google.api.HttpBody" {
93-
return "200", wk.NewGoogleApiHttpBodyMediaType()
93+
return "200", wellknown.NewGoogleApiHttpBodyMediaType()
9494
}
9595

96-
return "200", wk.NewApplicationJsonMediaType(r.schemaOrReferenceForMessage(message))
96+
return "200", wellknown.NewApplicationJsonMediaType(r.schemaOrReferenceForMessage(message))
9797
}
9898

9999
func (r *OpenAPIv3Reflector) schemaReferenceForMessage(message protoreflect.MessageDescriptor) string {
@@ -110,44 +110,44 @@ func (r *OpenAPIv3Reflector) schemaOrReferenceForMessage(message protoreflect.Me
110110
typeName := fullMessageTypeName(message)
111111
switch typeName {
112112
case ".google.api.HttpBody":
113-
return wk.NewGoogleApiHttpBodySchema()
113+
return wellknown.NewGoogleApiHttpBodySchema()
114114

115115
case ".google.protobuf.Timestamp":
116-
return wk.NewGoogleProtobufTimestampSchema()
116+
return wellknown.NewGoogleProtobufTimestampSchema()
117117

118118
case ".google.protobuf.Duration":
119-
return wk.NewGoogleProtobufDurationSchema()
119+
return wellknown.NewGoogleProtobufDurationSchema()
120120

121121
case ".google.type.Date":
122-
return wk.NewGoogleTypeDateSchema()
122+
return wellknown.NewGoogleTypeDateSchema()
123123

124124
case ".google.type.DateTime":
125-
return wk.NewGoogleTypeDateTimeSchema()
125+
return wellknown.NewGoogleTypeDateTimeSchema()
126126

127127
case ".google.protobuf.FieldMask":
128-
return wk.NewGoogleProtobufFieldMaskSchema()
128+
return wellknown.NewGoogleProtobufFieldMaskSchema()
129129

130130
case ".google.protobuf.Struct":
131-
return wk.NewGoogleProtobufStructSchema()
131+
return wellknown.NewGoogleProtobufStructSchema()
132132

133133
case ".google.protobuf.Empty":
134134
// Empty is closer to JSON undefined than null, so ignore this field
135135
return nil //&v3.SchemaOrReference{Oneof: &v3.SchemaOrReference_Schema{Schema: &v3.Schema{Type: "null"}}}
136136

137137
case ".google.protobuf.BoolValue":
138-
return wk.NewBooleanSchema()
138+
return wellknown.NewBooleanSchema()
139139

140140
case ".google.protobuf.BytesValue":
141-
return wk.NewBytesSchema()
141+
return wellknown.NewBytesSchema()
142142

143143
case ".google.protobuf.Int32Value", ".google.protobuf.UInt32Value":
144-
return wk.NewIntegerSchema(getValueKind(message))
144+
return wellknown.NewIntegerSchema(getValueKind(message))
145145

146146
case ".google.protobuf.StringValue", ".google.protobuf.Int64Value", ".google.protobuf.UInt64Value":
147-
return wk.NewStringSchema()
147+
return wellknown.NewStringSchema()
148148

149149
case ".google.protobuf.FloatValue", ".google.protobuf.DoubleValue":
150-
return wk.NewNumberSchema(getValueKind(message))
150+
return wellknown.NewNumberSchema(getValueKind(message))
151151

152152
default:
153153
ref := r.schemaReferenceForMessage(message)
@@ -180,40 +180,40 @@ func (r *OpenAPIv3Reflector) schemaOrReferenceForField(field *protogen.Field, de
180180
//
181181
// So we need to find the `value` field in the `MapFieldEntry` message and
182182
// then return a MapFieldEntry schema using the schema for the `value` field
183-
return wk.NewGoogleProtobufMapFieldEntrySchema(r.schemaOrReferenceForField(field, desc.MapValue()))
183+
return wellknown.NewGoogleProtobufMapFieldEntrySchema(r.schemaOrReferenceForField(field, desc.MapValue()))
184184
} else {
185185
kindSchema = r.schemaOrReferenceForMessage(desc.Message())
186186
}
187187

188188
case protoreflect.StringKind:
189-
kindSchema = wk.NewStringSchema()
189+
kindSchema = wellknown.NewStringSchema()
190190

191191
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Uint32Kind,
192192
protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind:
193-
kindSchema = wk.NewIntegerSchema(kind.String())
193+
kindSchema = wellknown.NewIntegerSchema(kind.String())
194194

195195
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
196196
protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind:
197-
kindSchema = wk.NewStringSchema()
197+
kindSchema = wellknown.NewStringSchema()
198198

199199
case protoreflect.EnumKind:
200-
kindSchema = wk.NewEnumSchema(r.conf.EnumType, field)
200+
kindSchema = wellknown.NewEnumSchema(r.conf.EnumType, field)
201201

202202
case protoreflect.BoolKind:
203-
kindSchema = wk.NewBooleanSchema()
203+
kindSchema = wellknown.NewBooleanSchema()
204204

205205
case protoreflect.FloatKind, protoreflect.DoubleKind:
206-
kindSchema = wk.NewNumberSchema(kind.String())
206+
kindSchema = wellknown.NewNumberSchema(kind.String())
207207

208208
case protoreflect.BytesKind:
209-
kindSchema = wk.NewBytesSchema()
209+
kindSchema = wellknown.NewBytesSchema()
210210

211211
default:
212212
log.Printf("(TODO) Unsupported field type: %+v", fullMessageTypeName(field.Desc.Message()))
213213
}
214214

215215
if field.Desc.IsList() {
216-
kindSchema = wk.NewListSchema(kindSchema)
216+
kindSchema = wellknown.NewListSchema(kindSchema)
217217
}
218218

219219
return kindSchema

0 commit comments

Comments
 (0)