From 1a630258f45d118edbf6a9726106f916ccba1961 Mon Sep 17 00:00:00 2001 From: Jieping Lu Date: Wed, 3 Apr 2024 23:50:47 -0500 Subject: [PATCH] fix: fetch field property option for path variable and query (#436) --- .../tests/openapiv3annotations/message.proto | 20 +++++++++++ .../tests/openapiv3annotations/openapi.yaml | 35 +++++++++++++++++++ .../openapi_default_response.yaml | 35 +++++++++++++++++++ .../openapi_fq_schema_naming.yaml | 35 +++++++++++++++++++ .../openapiv3annotations/openapi_json.yaml | 35 +++++++++++++++++++ .../openapi_string_enum.yaml | 35 +++++++++++++++++++ cmd/protoc-gen-openapi/generator/generator.go | 11 +++++- 7 files changed, 205 insertions(+), 1 deletion(-) diff --git a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/message.proto b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/message.proto index fa9f6f0f..21c931c8 100644 --- a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/message.proto +++ b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/message.proto @@ -75,6 +75,13 @@ service Messaging1 { ] }; } + // while field in message has overriden field, it should reflect in "parameters" section + rpc GetMessageById(Message2) returns(Message2) { + option(google.api.http) = { + // id should have limit since id in message2 have the limit + get: "/v1/messages2/{id}" + }; + } } service Messaging2 { @@ -94,3 +101,16 @@ message Message { } ]; } + +message Message2 { + option (openapi.v3.schema) = { + title: "This is an overridden message schema title"; + }; + + string id = 1 [ + (openapi.v3.property) = { + title: "this is an overriden field schema title"; + max_length: 255; + } + ]; +} diff --git a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi.yaml b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi.yaml index b1e31f0f..7c341f61 100644 --- a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi.yaml @@ -46,6 +46,33 @@ paths: $ref: '#/components/schemas/Status' security: - BasicAuth: [] + /v1/messages2/{id}: + get: + tags: + - Messaging1 + description: while field in message has overriden field, it should reflect in "parameters" section + operationId: Messaging1_GetMessageById + parameters: + - name: id + in: path + required: true + schema: + title: this is an overriden field schema title + maxLength: 255 + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Message2' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' components: schemas: GoogleProtobufAny: @@ -66,6 +93,14 @@ components: title: this is an overriden field schema title maxLength: 255 type: string + Message2: + title: This is an overridden message schema title + type: object + properties: + id: + title: this is an overriden field schema title + maxLength: 255 + type: string Status: type: object properties: 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..7c341f61 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 @@ -46,6 +46,33 @@ paths: $ref: '#/components/schemas/Status' security: - BasicAuth: [] + /v1/messages2/{id}: + get: + tags: + - Messaging1 + description: while field in message has overriden field, it should reflect in "parameters" section + operationId: Messaging1_GetMessageById + parameters: + - name: id + in: path + required: true + schema: + title: this is an overriden field schema title + maxLength: 255 + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Message2' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' components: schemas: GoogleProtobufAny: @@ -66,6 +93,14 @@ components: title: this is an overriden field schema title maxLength: 255 type: string + Message2: + title: This is an overridden message schema title + type: object + properties: + id: + title: this is an overriden field schema title + maxLength: 255 + type: string Status: type: object properties: 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..311275b6 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 @@ -46,6 +46,33 @@ paths: $ref: '#/components/schemas/google.rpc.Status' security: - BasicAuth: [] + /v1/messages2/{id}: + get: + tags: + - Messaging1 + description: while field in message has overriden field, it should reflect in "parameters" section + operationId: Messaging1_GetMessageById + parameters: + - name: id + in: path + required: true + schema: + title: this is an overriden field schema title + maxLength: 255 + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/tests.openapiv3annotations.message.v1.Message2' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/google.rpc.Status' components: schemas: google.protobuf.Any: @@ -82,6 +109,14 @@ components: title: this is an overriden field schema title maxLength: 255 type: string + tests.openapiv3annotations.message.v1.Message2: + title: This is an overridden message schema title + type: object + properties: + id: + title: this is an overriden field schema title + maxLength: 255 + type: string securitySchemes: BasicAuth: type: http 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..7c341f61 100644 --- a/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_json.yaml +++ b/cmd/protoc-gen-openapi/examples/tests/openapiv3annotations/openapi_json.yaml @@ -46,6 +46,33 @@ paths: $ref: '#/components/schemas/Status' security: - BasicAuth: [] + /v1/messages2/{id}: + get: + tags: + - Messaging1 + description: while field in message has overriden field, it should reflect in "parameters" section + operationId: Messaging1_GetMessageById + parameters: + - name: id + in: path + required: true + schema: + title: this is an overriden field schema title + maxLength: 255 + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Message2' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' components: schemas: GoogleProtobufAny: @@ -66,6 +93,14 @@ components: title: this is an overriden field schema title maxLength: 255 type: string + Message2: + title: This is an overridden message schema title + type: object + properties: + id: + title: this is an overriden field schema title + maxLength: 255 + type: string Status: type: object properties: 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..7c341f61 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 @@ -46,6 +46,33 @@ paths: $ref: '#/components/schemas/Status' security: - BasicAuth: [] + /v1/messages2/{id}: + get: + tags: + - Messaging1 + description: while field in message has overriden field, it should reflect in "parameters" section + operationId: Messaging1_GetMessageById + parameters: + - name: id + in: path + required: true + schema: + title: this is an overriden field schema title + maxLength: 255 + type: string + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Message2' + default: + description: Default error response + content: + application/json: + schema: + $ref: '#/components/schemas/Status' components: schemas: GoogleProtobufAny: @@ -66,6 +93,14 @@ components: title: this is an overriden field schema title maxLength: 255 type: string + Message2: + title: This is an overridden message schema title + type: object + properties: + id: + title: this is an overriden field schema title + maxLength: 255 + type: string Status: type: object properties: diff --git a/cmd/protoc-gen-openapi/generator/generator.go b/cmd/protoc-gen-openapi/generator/generator.go index e548ab21..48b6a2f9 100644 --- a/cmd/protoc-gen-openapi/generator/generator.go +++ b/cmd/protoc-gen-openapi/generator/generator.go @@ -415,7 +415,7 @@ func (g *OpenAPIv3Generator) _buildQueryParamsV3(field *protogen.Field, depths m } else if field.Desc.Kind() != protoreflect.GroupKind { // schemaOrReferenceForField also handles array types fieldSchema := g.reflect.schemaOrReferenceForField(field.Desc) - + enrichFieldSchema(field, fieldSchema) parameters = append(parameters, &v3.ParameterOrReference{ Oneof: &v3.ParameterOrReference_Parameter{ @@ -433,6 +433,14 @@ func (g *OpenAPIv3Generator) _buildQueryParamsV3(field *protogen.Field, depths m return parameters } +func enrichFieldSchema(field *protogen.Field, fieldSchema *v3.SchemaOrReference) { + // Merge any `Property` annotations with the current + extProperty := proto.GetExtension(field.Desc.Options(), v3.E_Property) + if extProperty != nil { + proto.Merge(fieldSchema.GetSchema(), extProperty.(*v3.Schema)) + } +} + // buildOperationV3 constructs an operation for a set of values. func (g *OpenAPIv3Generator) buildOperationV3( d *v3.Document, @@ -468,6 +476,7 @@ func (g *OpenAPIv3Generator) buildOperationV3( field := g.findField(pathParameter, inputMessage) if field != nil { fieldSchema = g.reflect.schemaOrReferenceForField(field.Desc) + enrichFieldSchema(field, fieldSchema) fieldDescription = g.filterCommentString(field.Comments.Leading) } else { // If field does not exist, it is safe to set it to string, as it is ignored downstream