Skip to content

protoc-gen-openapi: path parameters are repeated in the body when using body: "*" #323

Description

@istvan-hevele

When a request has both path parameters and body: "*", the path parameters are being repeated in the body in the resulting OpenAPI spec.
Note how the following example has name both in parameters and requestBody in the generated openapi spec.

protobuf:

service LibraryService {
  rpc MergeShelves(MergeShelvesRequest) return (Shelf) {
    option (google.api.http) = {
      post: "/v1/{name=shelves/*}:merge"
      body: "*"
    };
  }
}

// Describes the shelf being removed (other_shelf_name) and updated
// (name) in this merge.
message MergeShelvesRequest {
  // The name of the shelf we're adding books to.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference).type = "Shelf"
  ];

  // The name of the shelf we're removing books from and deleting.
  string other_shelf_name = 2 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference).type = "Shelf"
  ];
}

openapi spec:

paths:
    /v1/shelves/{shelf}:merge:
        post:
            tags:
                - LibraryService
            description: |-
                Merges two shelves by adding all books from the shelf named
                 `other_shelf_name` to shelf `name`, and deletes
                 `other_shelf_name`. Returns the updated shelf.
                 The book ids of the moved books may not be the same as the original books.
                 Returns NOT_FOUND if either shelf does not exist.
                 This call is a no-op if the specified shelves are the same.
            operationId: LibraryService_MergeShelves
            parameters:
                - name: shelf
                  in: path
                  description: The shelf id.
                  required: true
                  schema:
                    type: string
            requestBody:
                content:
                    application/json:
                        schema:
                            $ref: '#/components/schemas/MergeShelvesRequest'
                required: true
            responses:
                "200":
                    description: OK
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/Shelf'
components:
    schemas:
        MergeShelvesRequest:
            required:
                - name
                - other_shelf_name
            type: object
            properties:
                name:
                    type: string
                    description: The name of the shelf we're adding books to.
                other_shelf_name:
                    type: string
                    description: The name of the shelf we're removing books from and deleting.
            description: Describes the shelf being removed (other_shelf_name) and updated (name) in this merge.

According to use_wildcard_in_body, every field not bound by the path template should be mapped to the request body.
So fields that are bound by the path template shouldn't be in the request body.

Proposal:
In these cases, create a new schema named {method_name}RequestBody which doesn't contain the fields bound by the path:

paths:
    /v1/shelves/{shelf}:merge:
        post:
            tags:
                - LibraryService
            description: |-
                Merges two shelves by adding all books from the shelf named
                 `other_shelf_name` to shelf `name`, and deletes
                 `other_shelf_name`. Returns the updated shelf.
                 The book ids of the moved books may not be the same as the original books.

                 Returns NOT_FOUND if either shelf does not exist.
                 This call is a no-op if the specified shelves are the same.
            operationId: LibraryService_MergeShelves
            parameters:
                - name: shelf
                  in: path
                  description: The shelf id.
                  required: true
                  schema:
                    type: string
            requestBody:
                content:
                    application/json:
                        schema:
                            $ref: '#/components/schemas/MergeShelvesRequestBody'
                required: true
            responses:
                "200":
                    description: OK
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/Shelf'
components:
    schemas:
        MergeShelvesRequestBody:
            required:
                - other_shelf_name
            type: object
            properties:
                other_shelf_name:
                    type: string
                    description: The name of the shelf we're removing books from and deleting.
            description: Describes the shelf being removed (other_shelf_name) and updated (name) in this merge.

There's a PR on my fork that implements this proposal: istvan-hevele#1

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions