grpc-gateway icon indicating copy to clipboard operation
grpc-gateway copied to clipboard

Merged swagger outputs only require info of first proto file that is input

Open llsj14 opened this issue 2 years ago • 8 comments

🐛 Bug Report

Thanks for the great help and guide, I could merge swagger outputs of different services.

By the way, the problem is that the merged output only shows the service info of the proto file that is used as the first input. If I don't write down service info of first proto file into .swagger.yaml file, swagger output (.swagger.json) does not show any info. I'm curious about the intended behavior and the best practice. For example, if I have many services in an API group, and let's assume that new proto files are added, I should be aware of the first proto file(first in the alphabetic order) that is used for making swagger output. Moreover, the first proto file is not always a neutral one that represents whole proto files in an API group.

To Reproduce

There are a.proto, b.proto, c.proto

If swagger.yaml doesn't describe a.proto file like the following examples, any info will not show up in the swagger.json file.

openapiOptions:
  file:
  - file: "api/v1/b.proto"
    option:
      info:
        title: API
        version: "v1"
      schemes:
      - HTTPS
      - HTTP
      consumes:
      - application/json
      produces:
      - application/json
openapiOptions:
  file:
  - file: "api/v1/a.proto"
  - file: "api/v1/b.proto"
    option:
      info:
        title: API
        version: "v1"
      schemes:
      - HTTPS
      - HTTP
      consumes:
      - application/json
      produces:
      - application/json
  - file: "api/v1/c.proto"

Expected behavior

While merging swagger output, every possible service info is showed up

Actual Behavior

While merging swagger output, only service info that is input as the first proto file is showed up

Your Environment

macOS go1.16 darwin/amd64

llsj14 avatar Apr 01 '22 10:04 llsj14

Hi, thanks for the issue! This is annoying yes, but it's also not clear what the behavior should be. Merging all the info from all the files would potentially cause duplicate information to appear in the merged file. It would make sense for us to use the info from the first file found, so that any file could contain the information, don't you think?

If you'd like to help contribute a fix to this, feel free to start by creating an error case. We have a merge test proto here: https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/internal/proto/examplepb/openapi_merge.swagger.json, you could try annotating conflicting information in https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/internal/proto/examplepb/openapi_merge_a.proto and https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/internal/proto/examplepb/openapi_merge_b.proto and iterate on your fix.

johanbrandhorst avatar Apr 01 '22 22:04 johanbrandhorst

I agree with the way to block duplicated information to be appeared in the merged file and to use the info from the first file found. I'm also relieved that I didn't use your program in a wrong way. However, how about just giving chance to write specific proto file name(which is not first file found) on the swagger.yaml file and make it possible to use that information? Thinking about the situation where you add new proto files in an API group, I guess it is better to write down a specific proto file name, which is quite representative or neutral on the swagger.yaml file and use that information.

If you like this way as a good solution, I would like to contribute a fix as you guided.

llsj14 avatar Apr 04 '22 15:04 llsj14

However, how about just giving chance to write specific proto file name(which is not first file found) on the swagger.yaml file and make it possible to use that information?

I'm not sure what you mean by this. Do you mean adding a new option to protoc-gen-openapiv2? Something like merge_file_canonical_source=./the/specific/file.proto? I would really like to avoid adding more options, we already have too many and they're hard to understand for new users.

I think the most obvious algorithm for the information is to pick the first time some information is populated in any of the files. That would allow users to pick a single file to add all the annotations to. If they annotate more than one file, whichever one is processed first will win, which kind of sucks but adding an error or something would be a breaking change so we don't have much choice there.

What do you think?

johanbrandhorst avatar Apr 05 '22 01:04 johanbrandhorst

I didn't think about a new option and I also think it is complex. How about just making users pick a single file to add the information on the .swagger.yaml file. At this moment, there is no chance of that.

Let's say there's a.proto and b.proto. If I wanted to pick b.proto as representative proto file on the .swagger.yaml file and describe information about it, .swagger.json file will not give any information because it is not the first file in alphabetic order. I think making protoc-gen-openapiv2 use the information of first file on .swagger.yaml file will be enough.

  • as-is
<api.swagger.yaml>
openapiOptions:
  file:
  - file: "api/v1/b.proto"
    option:
      info:
        title: API
        version: "v1"

<api.swagger.json>
  "swagger": "2.0",
  "info": {
    "title": "api/v1/a.proto",
    "version": "version not set"
  },
  • to-be
<api.swagger.yaml>
openapiOptions:
  file:
  - file: "api/v1/b.proto"
    option:
      info:
        title: API
        version: "v1"

<api.swagger.json>
  "swagger": "2.0",
  "info": {
    "title": "API",
    "version": "v1"
  },

llsj14 avatar Apr 05 '22 05:04 llsj14

Now I'm really confused. Are you talking about our external openapi configuration file option? Under normal operation, there is no api.swagger.yaml as an input to the operation. When using the openapi_configuration option, you can specify your annotations in an external file rather than as annotations in the protobuf file. Of course, in this scenario, the settings in the openapi_configuration should be respected, but it's not clear to me that they should take precedent over annotations in the files themselves. What happens if annotations are present in one of the files and you use the external configuration file?

External openapi configuration file example: https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml Internal openapi annotation example: https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/internal/proto/examplepb/a_bit_of_everything.proto

johanbrandhorst avatar Apr 05 '22 13:04 johanbrandhorst

Oh, I'm sorry, if I made you confused. I only used your external openapi configuration file option. Because I didn't know your internal openapi annotation. I made our Makefile as below without any internal openapi annotaion.

%.swagger.json: $(dir %)*.proto %.swagger.yaml | grpc
	protoc --openapiv2_out . \
	       --openapiv2_opt logtostderr=true \
	       --openapiv2_opt openapi_configuration=$*.swagger.yaml \
	       --openapiv2_opt visibility_restriction_selectors=INTERNAL \
	       --openapiv2_opt allow_merge=true \
	       --openapiv2_opt merge_file_name=$* \
	       $(dir $*)*.proto \

I did the experiment you told me about. Inserting an internal annotation into one of the files takes precedence over the external openapi configuration. Therefore, I can use internal annotations to put information options in a specific file. Maybe I can just use this as a solution. Thank you!

In summary, if I only use an external openapi configuration, I cannot use the information of a specific file in the yaml file (even though it is the only information in yaml), because only the information in the alphabetically first file can be used.

llsj14 avatar Apr 05 '22 16:04 llsj14

Glad you found something that works for you. Would you be willing to contribute a documentation update to help other users? We document the merge file behavior here: https://github.com/grpc-ecosystem/grpc-gateway/blob/master/docs/docs/mapping/customizing_openapi_output.md#merging-output. Might be worth adding a small section about the merge priority.

johanbrandhorst avatar Apr 05 '22 18:04 johanbrandhorst

Yes, I would be willing to contribute a documentation update. Thank you.

llsj14 avatar Apr 06 '22 11:04 llsj14