From 1bfb35101aaf1c58f54891718fa3aea01651d811 Mon Sep 17 00:00:00 2001 From: KayanoLiam Date: Tue, 6 Oct 2026 13:06:40 +0900 Subject: [PATCH] fix: preserve numeric formats for 64-bit OpenAPI fields --- .../examples/tests/mapfields/openapi.yaml | 2 + .../mapfields/openapi_default_response.yaml | 2 + .../mapfields/openapi_fq_schema_naming.yaml | 2 + .../tests/mapfields/openapi_json.yaml | 2 + .../tests/mapfields/openapi_string_enum.yaml | 2 + .../examples/tests/noannotations/openapi.yaml | 1 + .../openapi_default_response.yaml | 1 + .../openapi_fq_schema_naming.yaml | 1 + .../tests/noannotations/openapi_json.yaml | 1 + .../noannotations/openapi_string_enum.yaml | 1 + .../tests/openapiv3annotations/openapi.yaml | 1 + .../openapi_default_response.yaml | 1 + .../openapi_fq_schema_naming.yaml | 1 + .../openapiv3annotations/openapi_json.yaml | 1 + .../openapi_string_enum.yaml | 1 + .../examples/tests/pathparams/openapi.yaml | 3 + .../pathparams/openapi_default_response.yaml | 3 + .../pathparams/openapi_fq_schema_naming.yaml | 3 + .../tests/pathparams/openapi_json.yaml | 3 + .../tests/pathparams/openapi_string_enum.yaml | 3 + .../examples/tests/protobuftypes/openapi.yaml | 6 + .../openapi_default_response.yaml | 6 + .../openapi_fq_schema_naming.yaml | 6 + .../tests/protobuftypes/openapi_json.yaml | 6 + .../protobuftypes/openapi_string_enum.yaml | 6 + cmd/protoc-gen-openapi/generator/reflector.go | 8 +- .../generator/reflector_test.go | 125 ++++++++++++++++++ .../generator/wellknown/schemas.go | 16 ++- 28 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 cmd/protoc-gen-openapi/generator/reflector_test.go diff --git a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi.yaml b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi.yaml index c63dc62e..78f1880e 100644 --- a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi.yaml @@ -43,6 +43,7 @@ components: properties: id: type: string + format: int64 label: type: string GoogleProtobufAny: @@ -91,6 +92,7 @@ components: properties: id: type: string + format: int64 label: type: string Status: diff --git a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_default_response.yaml b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_default_response.yaml index 4d510192..53676de7 100644 --- a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_default_response.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_default_response.yaml @@ -43,6 +43,7 @@ components: properties: id: type: string + format: int64 label: type: string GoogleProtobufAny: @@ -91,6 +92,7 @@ components: properties: id: type: string + format: int64 label: type: string Status: diff --git a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_fq_schema_naming.yaml b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_fq_schema_naming.yaml index 1c343d1e..c64829b6 100644 --- a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_fq_schema_naming.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_fq_schema_naming.yaml @@ -67,6 +67,7 @@ components: properties: id: type: string + format: int64 label: type: string tests.mapfields.message.v1.Message: @@ -107,6 +108,7 @@ components: properties: id: type: string + format: int64 label: type: string tags: diff --git a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_json.yaml b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_json.yaml index 8e8b796e..fc4834aa 100644 --- a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_json.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_json.yaml @@ -43,6 +43,7 @@ components: properties: id: type: string + format: int64 label: type: string GoogleProtobufAny: @@ -91,6 +92,7 @@ components: properties: id: type: string + format: int64 label: type: string Status: diff --git a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_string_enum.yaml b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_string_enum.yaml index 4d510192..53676de7 100644 --- a/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_string_enum.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/mapfields/openapi_string_enum.yaml @@ -43,6 +43,7 @@ components: properties: id: type: string + format: int64 label: type: string GoogleProtobufAny: @@ -91,6 +92,7 @@ components: properties: id: type: string + format: int64 label: type: string Status: diff --git a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi.yaml b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi.yaml index d00cbb93..dedf5a34 100644 --- a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi.yaml @@ -51,6 +51,7 @@ components: properties: id: type: string + format: int64 label: type: string Status: diff --git a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_default_response.yaml b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_default_response.yaml index d00cbb93..dedf5a34 100644 --- a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_default_response.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_default_response.yaml @@ -51,6 +51,7 @@ components: properties: id: type: string + format: int64 label: type: string Status: diff --git a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_fq_schema_naming.yaml b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_fq_schema_naming.yaml index 7f2e9e79..a081d79c 100644 --- a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_fq_schema_naming.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_fq_schema_naming.yaml @@ -67,6 +67,7 @@ components: properties: id: type: string + format: int64 label: type: string tags: diff --git a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_json.yaml b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_json.yaml index d7d35208..5ef9f3d0 100644 --- a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_json.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_json.yaml @@ -51,6 +51,7 @@ components: properties: id: type: string + format: int64 label: type: string Status: diff --git a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_string_enum.yaml b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_string_enum.yaml index d00cbb93..dedf5a34 100644 --- a/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_string_enum.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/noannotations/openapi_string_enum.yaml @@ -51,6 +51,7 @@ components: properties: id: type: string + format: int64 label: type: string Status: diff --git a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi.yaml b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi.yaml index b1e31f0f..345500b4 100644 --- a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi.yaml @@ -62,6 +62,7 @@ components: properties: id: type: string + format: int64 label: title: this is an overriden field schema title maxLength: 255 diff --git a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_default_response.yaml b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_default_response.yaml index b1e31f0f..345500b4 100644 --- a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_default_response.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_default_response.yaml @@ -62,6 +62,7 @@ components: properties: id: type: string + format: int64 label: title: this is an overriden field schema title maxLength: 255 diff --git a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_fq_schema_naming.yaml b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_fq_schema_naming.yaml index 5dbbceca..432dbd4e 100644 --- a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_fq_schema_naming.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_fq_schema_naming.yaml @@ -78,6 +78,7 @@ components: properties: id: type: string + format: int64 label: title: this is an overriden field schema title maxLength: 255 diff --git a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_json.yaml b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_json.yaml index b1e31f0f..345500b4 100644 --- a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_json.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_json.yaml @@ -62,6 +62,7 @@ components: properties: id: type: string + format: int64 label: title: this is an overriden field schema title maxLength: 255 diff --git a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_string_enum.yaml b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_string_enum.yaml index b1e31f0f..345500b4 100644 --- a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_string_enum.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_string_enum.yaml @@ -62,6 +62,7 @@ components: properties: id: type: string + format: int64 label: title: this is an overriden field schema title maxLength: 255 diff --git a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi.yaml b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi.yaml index f65b66d2..70a7182e 100644 --- a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi.yaml @@ -21,6 +21,7 @@ paths: in: query schema: type: string + format: uint64 responses: "200": description: OK @@ -74,6 +75,7 @@ paths: required: true schema: type: string + format: uint64 - name: message_id in: path required: true @@ -109,6 +111,7 @@ components: type: string user_id: type: string + format: uint64 content: type: string maybe: diff --git a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_default_response.yaml b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_default_response.yaml index 470bab61..c0762b03 100644 --- a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_default_response.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_default_response.yaml @@ -21,6 +21,7 @@ paths: in: query schema: type: string + format: uint64 responses: "200": description: OK @@ -74,6 +75,7 @@ paths: required: true schema: type: string + format: uint64 - name: messageId in: path required: true @@ -109,6 +111,7 @@ components: type: string userId: type: string + format: uint64 content: type: string maybe: diff --git a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_fq_schema_naming.yaml b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_fq_schema_naming.yaml index f682585d..f23b4b5a 100644 --- a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_fq_schema_naming.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_fq_schema_naming.yaml @@ -21,6 +21,7 @@ paths: in: query schema: type: string + format: uint64 responses: "200": description: OK @@ -74,6 +75,7 @@ paths: required: true schema: type: string + format: uint64 - name: messageId in: path required: true @@ -125,6 +127,7 @@ components: type: string userId: type: string + format: uint64 content: type: string maybe: diff --git a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_json.yaml b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_json.yaml index ff7d0a3d..210fa9bd 100644 --- a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_json.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_json.yaml @@ -21,6 +21,7 @@ paths: in: query schema: type: string + format: uint64 responses: "200": description: OK @@ -74,6 +75,7 @@ paths: required: true schema: type: string + format: uint64 - name: messageId in: path required: true @@ -109,6 +111,7 @@ components: type: string userId: type: string + format: uint64 content: type: string maybe: diff --git a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_string_enum.yaml b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_string_enum.yaml index 470bab61..c0762b03 100644 --- a/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_string_enum.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/pathparams/openapi_string_enum.yaml @@ -21,6 +21,7 @@ paths: in: query schema: type: string + format: uint64 responses: "200": description: OK @@ -74,6 +75,7 @@ paths: required: true schema: type: string + format: uint64 - name: messageId in: path required: true @@ -109,6 +111,7 @@ components: type: string userId: type: string + format: uint64 content: type: string maybe: diff --git a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi.yaml b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi.yaml index 6cb6b7fb..b9c89e91 100644 --- a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi.yaml @@ -125,10 +125,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64_value_type in: query schema: type: string + format: uint64 - name: float_value_type in: query schema: @@ -290,10 +292,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64_value_type in: query schema: type: string + format: uint64 - name: float_value_type in: query schema: @@ -445,8 +449,10 @@ components: type: string int64_value_type: type: string + format: int64 uint64_value_type: type: string + format: uint64 float_value_type: type: number format: float diff --git a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_default_response.yaml b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_default_response.yaml index 1158893e..a8a23517 100644 --- a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_default_response.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_default_response.yaml @@ -125,10 +125,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64ValueType in: query schema: type: string + format: uint64 - name: floatValueType in: query schema: @@ -290,10 +292,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64ValueType in: query schema: type: string + format: uint64 - name: floatValueType in: query schema: @@ -445,8 +449,10 @@ components: type: string int64ValueType: type: string + format: int64 uint64ValueType: type: string + format: uint64 floatValueType: type: number format: float diff --git a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_fq_schema_naming.yaml b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_fq_schema_naming.yaml index bd276315..c63211c0 100644 --- a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_fq_schema_naming.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_fq_schema_naming.yaml @@ -125,10 +125,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64ValueType in: query schema: type: string + format: uint64 - name: floatValueType in: query schema: @@ -290,10 +292,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64ValueType in: query schema: type: string + format: uint64 - name: floatValueType in: query schema: @@ -461,8 +465,10 @@ components: type: string int64ValueType: type: string + format: int64 uint64ValueType: type: string + format: uint64 floatValueType: type: number format: float diff --git a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_json.yaml b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_json.yaml index ae946c55..bd2d52f5 100644 --- a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_json.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_json.yaml @@ -125,10 +125,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64ValueType in: query schema: type: string + format: uint64 - name: floatValueType in: query schema: @@ -290,10 +292,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64ValueType in: query schema: type: string + format: uint64 - name: floatValueType in: query schema: @@ -445,8 +449,10 @@ components: type: string int64ValueType: type: string + format: int64 uint64ValueType: type: string + format: uint64 floatValueType: type: number format: float diff --git a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_string_enum.yaml b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_string_enum.yaml index 1158893e..a8a23517 100644 --- a/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_string_enum.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/protobuftypes/openapi_string_enum.yaml @@ -125,10 +125,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64ValueType in: query schema: type: string + format: uint64 - name: floatValueType in: query schema: @@ -290,10 +292,12 @@ paths: in: query schema: type: string + format: int64 - name: uint64ValueType in: query schema: type: string + format: uint64 - name: floatValueType in: query schema: @@ -445,8 +449,10 @@ components: type: string int64ValueType: type: string + format: int64 uint64ValueType: type: string + format: uint64 floatValueType: type: number format: float diff --git a/cmd/protoc-gen-openapi/generator/reflector.go b/cmd/protoc-gen-openapi/generator/reflector.go index 31a0f930..69c17751 100644 --- a/cmd/protoc-gen-openapi/generator/reflector.go +++ b/cmd/protoc-gen-openapi/generator/reflector.go @@ -163,9 +163,12 @@ func (r *OpenAPIv3Reflector) schemaOrReferenceForMessage(message protoreflect.Me case ".google.protobuf.Int32Value", ".google.protobuf.UInt32Value": return wk.NewIntegerSchema(getValueKind(message)) - case ".google.protobuf.StringValue", ".google.protobuf.Int64Value", ".google.protobuf.UInt64Value": + case ".google.protobuf.StringValue": return wk.NewStringSchema() + case ".google.protobuf.Int64Value", ".google.protobuf.UInt64Value": + return wk.NewStringSchemaWithFormat(getValueKind(message)) + case ".google.protobuf.FloatValue", ".google.protobuf.DoubleValue": return wk.NewNumberSchema(getValueKind(message)) @@ -213,7 +216,8 @@ func (r *OpenAPIv3Reflector) schemaOrReferenceForField(field protoreflect.FieldD case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind, protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind: - kindSchema = wk.NewStringSchema() + // ProtoJSON encodes 64-bit integers as strings. + kindSchema = wk.NewStringSchemaWithFormat(kind.String()) case protoreflect.EnumKind: kindSchema = wk.NewEnumSchema(*&r.conf.EnumType, field) diff --git a/cmd/protoc-gen-openapi/generator/reflector_test.go b/cmd/protoc-gen-openapi/generator/reflector_test.go new file mode 100644 index 00000000..eaa8e4bc --- /dev/null +++ b/cmd/protoc-gen-openapi/generator/reflector_test.go @@ -0,0 +1,125 @@ +// Copyright 2026 Google LLC. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package generator + +import ( + "testing" + + v3 "github.com/google/gnostic/openapiv3" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protodesc" + "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/types/descriptorpb" + "google.golang.org/protobuf/types/known/wrapperspb" +) + +func TestSchemaOrReferenceForFieldFormats(t *testing.T) { + tests := []struct { + name string + kind descriptorpb.FieldDescriptorProto_Type + typeName string + wantType string + wantFormat string + }{ + {name: "int64", kind: descriptorpb.FieldDescriptorProto_TYPE_INT64, wantType: "string", wantFormat: "int64"}, + {name: "uint64", kind: descriptorpb.FieldDescriptorProto_TYPE_UINT64, wantType: "string", wantFormat: "uint64"}, + {name: "sint64", kind: descriptorpb.FieldDescriptorProto_TYPE_SINT64, wantType: "string", wantFormat: "sint64"}, + {name: "fixed64", kind: descriptorpb.FieldDescriptorProto_TYPE_FIXED64, wantType: "string", wantFormat: "fixed64"}, + {name: "sfixed64", kind: descriptorpb.FieldDescriptorProto_TYPE_SFIXED64, wantType: "string", wantFormat: "sfixed64"}, + {name: "string", kind: descriptorpb.FieldDescriptorProto_TYPE_STRING, wantType: "string"}, + {name: "int32", kind: descriptorpb.FieldDescriptorProto_TYPE_INT32, wantType: "integer", wantFormat: "int32"}, + {name: "uint32", kind: descriptorpb.FieldDescriptorProto_TYPE_UINT32, wantType: "integer", wantFormat: "uint32"}, + {name: "Int64Value", kind: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, typeName: ".google.protobuf.Int64Value", wantType: "string", wantFormat: "int64"}, + {name: "UInt64Value", kind: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, typeName: ".google.protobuf.UInt64Value", wantType: "string", wantFormat: "uint64"}, + {name: "StringValue", kind: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, typeName: ".google.protobuf.StringValue", wantType: "string"}, + {name: "Int32Value", kind: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, typeName: ".google.protobuf.Int32Value", wantType: "integer", wantFormat: "int32"}, + {name: "UInt32Value", kind: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE, typeName: ".google.protobuf.UInt32Value", wantType: "integer", wantFormat: "uint32"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + value := &descriptorpb.FieldDescriptorProto{ + Name: proto.String("value"), + Number: proto.Int32(1), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: tt.kind.Enum(), + } + if tt.typeName != "" { + value.TypeName = proto.String(tt.typeName) + } + values := proto.Clone(value).(*descriptorpb.FieldDescriptorProto) + values.Name = proto.String("values") + values.Number = proto.Int32(2) + values.Label = descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum() + mapValue := proto.Clone(value).(*descriptorpb.FieldDescriptorProto) + mapValue.Number = proto.Int32(2) + + file, err := protodesc.NewFile(&descriptorpb.FileDescriptorProto{ + Name: proto.String("test.proto"), + Package: proto.String("test"), + Syntax: proto.String("proto3"), + Dependency: []string{wrapperspb.File_google_protobuf_wrappers_proto.Path()}, + MessageType: []*descriptorpb.DescriptorProto{{ + Name: proto.String("Message"), + Field: []*descriptorpb.FieldDescriptorProto{value, values, { + Name: proto.String("values_by_key"), + Number: proto.Int32(3), + Label: descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_MESSAGE.Enum(), + TypeName: proto.String(".test.Message.ValuesByKeyEntry"), + }}, + NestedType: []*descriptorpb.DescriptorProto{{ + Name: proto.String("ValuesByKeyEntry"), + Options: &descriptorpb.MessageOptions{MapEntry: proto.Bool(true)}, + Field: []*descriptorpb.FieldDescriptorProto{{ + Name: proto.String("key"), + Number: proto.Int32(1), + Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(), + Type: descriptorpb.FieldDescriptorProto_TYPE_STRING.Enum(), + }, mapValue}, + }}, + }}, + }, protoregistry.GlobalFiles) + if err != nil { + t.Fatal(err) + } + + r := NewOpenAPIv3Reflector(Configuration{}) + fields := file.Messages().Get(0).Fields() + for i := 0; i < fields.Len(); i++ { + field := fields.Get(i) + t.Run(string(field.Name()), func(t *testing.T) { + schema := r.schemaOrReferenceForField(field).GetSchema() + switch { + case field.IsMap(): + if schema.GetType() != "object" { + t.Fatalf("map schema type = %q, want object", schema.GetType()) + } + schema = schema.GetAdditionalProperties().GetSchemaOrReference().GetSchema() + case field.IsList(): + items := schema.GetItems().GetSchemaOrReference() + if schema.GetType() != "array" || len(items) != 1 { + t.Fatalf("want array schema with one item schema, got %v", schema) + } + schema = items[0].GetSchema() + } + want := &v3.Schema{Type: tt.wantType, Format: tt.wantFormat} + if !proto.Equal(schema, want) { + t.Errorf("schema = %v, want %v", schema, want) + } + }) + } + }) + } +} diff --git a/cmd/protoc-gen-openapi/generator/wellknown/schemas.go b/cmd/protoc-gen-openapi/generator/wellknown/schemas.go index 8840dde8..26be2e67 100644 --- a/cmd/protoc-gen-openapi/generator/wellknown/schemas.go +++ b/cmd/protoc-gen-openapi/generator/wellknown/schemas.go @@ -21,9 +21,13 @@ import ( ) func NewStringSchema() *v3.SchemaOrReference { + return NewStringSchemaWithFormat("") +} + +func NewStringSchemaWithFormat(format string) *v3.SchemaOrReference { return &v3.SchemaOrReference{ Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "string"}}} + Schema: &v3.Schema{Type: "string", Format: format}}} } func NewBooleanSchema() *v3.SchemaOrReference { @@ -168,9 +172,12 @@ func NewGoogleProtobufStructSchema() *v3.SchemaOrReference { // google.protobuf.Value is handled specially // See here for the details on the JSON mapping: -// https://developers.google.com/protocol-buffers/docs/proto3#json +// +// https://developers.google.com/protocol-buffers/docs/proto3#json +// // and here: -// https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Value +// +// https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Value func NewGoogleProtobufValueSchema(name string) *v3.NamedSchemaOrReference { return &v3.NamedSchemaOrReference{ Name: name, @@ -186,7 +193,8 @@ func NewGoogleProtobufValueSchema(name string) *v3.NamedSchemaOrReference { // google.protobuf.Any is handled specially // See here for the details on the JSON mapping: -// https://developers.google.com/protocol-buffers/docs/proto3#json +// +// https://developers.google.com/protocol-buffers/docs/proto3#json func NewGoogleProtobufAnySchema(name string) *v3.NamedSchemaOrReference { return &v3.NamedSchemaOrReference{ Name: name,