Skip to content

[protoc-gen-openapiv2] Incorrectly generated OpenAPIv2 spec when using field_behaviour annotationΒ #3058

@jan-sykora

Description

@jan-sykora

πŸ› Bug Report

This is almost exactly the same error as in #1937:

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.

The #1937 is already resolved & closed but it seems this type of error was not resolved completely since I can reproduce it.

To Reproduce

I'm using Buf to deal with external dependencies (googleapis). But you should be able to reproduce it using only protoc, protoc-gen-openapiv2 and foo.proto, if you manually provide the googleapis.

Here's the whole Buf setup:

.
β”œβ”€β”€ buf.gen.yaml
β”œβ”€β”€ buf.work.yaml
└── proto
    β”œβ”€β”€ buf.lock
    β”œβ”€β”€ buf.yaml
    └── v1
        └── foo.proto

buf.gen.yaml

version: v1
managed:
  enabled: true
  go_package_prefix:
    default: github.com/foo
plugins:
  - name: openapiv2
    out: gen

buf.work.yaml

version: v1
directories:
  - proto

proto/buf.yaml

version: v1
deps:
  - buf.build/googleapis/googleapis

proto/buf.lock

Is generated by command:

cd proto && buf mod update

example content:

# Generated by buf. DO NOT EDIT.
version: v1
deps:
  - remote: buf.build
    owner: googleapis
    repository: googleapis
    commit: faacf837d7304c58b7c9020c7807fa6e

proto/v1/foo.proto

syntax = "proto3";

package v1;

import "google/api/annotations.proto";
import "google/api/field_behavior.proto";

message Foo {
}

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

service FooService {
  rpc CreateFoo (CreateFooRequest) returns (Foo) {
    option (google.api.http) = {
      post: "/v1/foos"
      body: "foo"
    };
  }
}

Finally, generate openapiv2 via buf command:

buf generate

(you should be also able to generate directly by using protoc but you have to provide the googleapis deps)

Expected behavior

gen/v1/foo.swagger.json

{
  "swagger": "2.0",
  "info": {
    "title": "v1/foo.proto",
    "version": "version not set"
  },
  "tags": [
    {
      "name": "FooService"
    }
  ],
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/v1/foos": {
      "post": {
        "operationId": "FooService_CreateFoo",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1Foo"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "foo",
            "in": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/v1Foo",
            }
          }
        ],
        "tags": [
          "FooService"
        ]
      }
    }
  },
  "definitions": {
    "protobufAny": {
      "type": "object",
      "properties": {
        "@type": {
          "type": "string"
        }
      },
      "additionalProperties": {}
    },
    "rpcStatus": {
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "format": "int32"
        },
        "message": {
          "type": "string"
        },
        "details": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/protobufAny"
          }
        }
      }
    },
    "v1Foo": {
      "type": "object"
    }
  }
}

Actual Behavior

gen/v1/foo.swagger.json

{
  "swagger": "2.0",
  "info": {
    "title": "v1/foo.proto",
    "version": "version not set"
  },
  "tags": [
    {
      "name": "FooService"
    }
  ],
  "consumes": [
    "application/json"
  ],
  "produces": [
    "application/json"
  ],
  "paths": {
    "/v1/foos": {
      "post": {
        "operationId": "FooService_CreateFoo",
        "responses": {
          "200": {
            "description": "A successful response.",
            "schema": {
              "$ref": "#/definitions/v1Foo"
            }
          },
          "default": {
            "description": "An unexpected error response.",
            "schema": {
              "$ref": "#/definitions/rpcStatus"
            }
          }
        },
        "parameters": [
          {
            "name": "foo",
            "in": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/v1Foo",
              "required": [ <-- THIS SHOULDN'T BE HERE
                "foo"           
              ]
            }
          }
        ],
        "tags": [
          "FooService"
        ]
      }
    }
  },
  "definitions": {
    "protobufAny": {
      "type": "object",
      "properties": {
        "@type": {
          "type": "string"
        }
      },
      "additionalProperties": {}
    },
    "rpcStatus": {
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "format": "int32"
        },
        "message": {
          "type": "string"
        },
        "details": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/protobufAny"
          }
        }
      }
    },
    "v1Foo": {
      "type": "object"
    }
  }
}

Your Environment

buf version: 1.10.0
protoc-gen-openapiv2 version: v2.14.0
go version: go1.19.1 darwin/amd64

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions