Skip to content

[protoc-gen-openapiv2] [BUG] Incorrect handling of non-wildcard google.api.http.body when using field_behaviour annotation #1937

Closed
@gganley

Description

@gganley

🐛 Bug Report

With the introduction of #1806 rpc definitions definitions that have a non-wildcard body property now fail validation. The generated code breaks because it produces a swagger document whose body parameter is a reference to the request definition but also has a required entry in the object.

Note that this file swagger file failed npx @opernapitools/openapi-generator-cli generate with error saying that required is unexpected.

To Reproduce

Proto File (./genproto/test/v1alpha/test.proto)

syntax = "proto3";

package example.test.v1alpha;

import "google/api/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/field_mask.proto";
import "protoc-gen-openapiv2/options/annotations.proto";

option go_package = "gitlab.com/example/example/genproto/test/v1alpha;test";
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = {
  host: "api.example.com"
  schemes: HTTPS,
};

service Test {
  rpc UpdateFoo(UpdateFooRequest) returns (Foo) {
    option (google.api.http) = {
      patch: "/v1alpha/foo/{foo.id}",
      body: "foo"
    };
    option (google.api.method_signature) = "foo,update_mask";
  }
}

message UpdateFooRequest {
  Foo foo = 1 [(google.api.field_behavior) = REQUIRED];

  google.protobuf.FieldMask update_mask = 2;
}

// Foo test.
message Foo {
  option (google.api.resource) = {
    type: "api.example.com/Foo"
    pattern: "foo/{id}"
  };

  int64 id = 1;
}

Run

 protoc -I. --openapiv2_out . --openapiv2_opt logtostderr=true ./genproto/test/v1alpha/test.proto

Expected behavior

{
  "swagger": "2.0",
  "info": {
    "title": "genproto/test/v1alpha/test.proto",
    "version": "version not set"
  },
  "tags": [
    {
      "name": "Test"
    }
  ],
  "host": "api.example.com",
  "schemes": [
    "https"
  ],
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/v1alpha/foo/{foo.id}": {
      "patch": {
        "operationId": "Test_UpdateFoo",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1alphaFoo"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "foo.id",
            "in": "path",
            "required": true,
            "type": "string",
            "format": "int64"
          },
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/v1alphaUpdateFooRequest"
            }
          }
        ],
        "tags": [
          "Test"
        ]
      }
    }
  },
  "definitions": {
    "protobufAny": {
      "type": "object",
      "properties": {
        "typeUrl": {
          "type": "string"
        },
        "value": {
          "type": "string",
          "format": "byte"
        }
      }
    },
    "rpcStatus": {
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "format": "int32"
        },
        "message": {
          "type": "string"
        },
        "details": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/protobufAny"
          }
        }
      }
    },
    "v1alphaFoo": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "format": "int64"
        }
      },
      "description": "Foo test."
    },
    "v1alphaUpdateFooRequest": {
      "type": "object",
      "properties": {
        "foo": {
          "$ref": "#/definitions/v1alphaFoo",
          "required": [
            "foo"
          ]
        },
        "updateMask": {
          "type": "string"
        }
      },
      "required": [
        "foo"
      ]
    }
  }
}

Actual Behavior

Note the schema change under the request parameters

{
  "swagger": "2.0",
  "info": {
    "title": "genproto/test/v1alpha/test.proto",
    "version": "version not set"
  },
  "tags": [
    {
      "name": "Test"
    }
  ],
  "host": "api.example.com",
  "schemes": [
    "https"
  ],
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/v1alpha/foo/{foo.id}": {
      "patch": {
        "operationId": "Test_UpdateFoo",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1alphaFoo"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "foo.id",
            "in": "path",
            "required": true,
            "type": "string",
            "format": "int64"
          },
          {
            "name": "body",
            "in": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/v1alphaFoo",
              "required": [ // !!!!! here is the issue, "$ref" should be alone here
                "foo"
              ]
            }
          },
          {
            "name": "updateMask",
            "in": "query",
            "required": false,
            "type": "string"
          }
        ],
        "tags": [
          "Test"
        ]
      }
    }
  },
  "definitions": {
    "protobufAny": {
      "type": "object",
      "properties": {
        "typeUrl": {
          "type": "string"
        },
        "value": {
          "type": "string",
          "format": "byte"
        }
      }
    },
    "rpcStatus": {
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "format": "int32"
        },
        "message": {
          "type": "string"
        },
        "details": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/protobufAny"
          }
        }
      }
    },
    "v1alphaFoo": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "format": "int64"
        }
      },
      "description": "Foo test."
    }
  }
}

Your Environment

(Environment name, version and operating system.)

uname -a: Linux 1319df9505dc 4.19.104-microsoft-standard #1 SMP Wed Feb 19 06:37:35 UTC 2020 x86_64 GNU/Linux

go version: 1.13.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions