简体   繁体   中英

How to generate swagger3 (OpenAPI3) spec in (.json/.yaml) from protobuf (.proto) files?

My original use-case:

I am building an application in GO with a gRPC server (using protobuf ), and wrapping it inside an HTTPS server (using gin ). Only the HTTPS server is being published to the clients for use (by which I mean that my application can be accessed via REST API, that actually then dials on the gRPC endpoint), and I am publishing it using Swagger OpenAPI3 (version 3 is the main requirement here) specification. Both gRPC and HTTPS is required, and any solution should adhere to this architecture.

I don't want to maintain my server specification at two places, that is I don't want to maintain both proto files ( .proto ) and swagger spec ( .json/.yaml ). Since I absolutely have to write proto files to generate gRPC server, I want to automate the swagger spec generation (OpenAPI3).

Where I am:

I am able to generate swagger OpenAPI2 spec from protobuf files ( .proto ) using grpc-gateway library something like so: grpc-rest-go-example . But my requirement is OpenAPI3; more specifically I want to use the oneOf feature in OpenAPI3 and map to it from oneof feature of proto. This is not possible with OpenAPI2, as it does not allow an API to have a request/response body of multiple type definitions, which was a feature added in OpenAPI3 by enabling oneOf, anyOf and allOf constructs.

While trying to do so, I stumbled upon this library by GoogleAPIs googleapis/gnostic , the description for which is:

This repository contains a Go command line tool which converts JSON and YAML OpenAPI descriptions to and from equivalent Protocol Buffer representations.

At first look, this seems to exactly solve my problem, but as it turns out, this library only interconverts between protocol buffer (protobuf) binary ( .pb ) and swagger OpenAPI2/OpenAPI3 ( .json/.yaml ) files, which brings me to my new problem.

So for example for the following .pb file:


�3.0.1�…�
�Example service��Example service description*�
�Example contact2=

Apache 2.0�/http://www.apache.org/licenses/LICENSE-2.0.html:�1.0�!
�//localhost:9999/example/api/v1"â�
�
�/exampleResource��"���Example API��Example API description*�example-operation2B
@
example-query��query��example-query description �R�
    Ê��stringBÇ��œ�
�200�”�
‘�
�OK�Š�
C
�application/json�/
-�+
)#/components/schemas/common.StatusMessage
C
�application/yaml�/
-�+
)#/components/schemas/common.StatusMessage�¥�
�400���
š�
�Bad Request�Š�
C
�application/json�/
-�+
)#/components/schemas/common.StatusMessage
C
�application/yaml�/
-�+
)#/components/schemas/common.StatusMessage*Y
W
U
�common.StatusMessage�=
;Ê��objectú�/
�
�message��
    ��string
�
�status��
    ��string

it generates the following swagger file:

openapi: 3.0.1
info:
  title: Example service
  description: Example service description
  contact:
    name: Example contact
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: "1.0"
servers:
- url: //localhost:9999/example/api/v1
paths:
  /exampleResource:
    get:
      summary: Example API
      description: Example API description
      operationId: example-operation
      parameters:
      - name: example-query
        in: query
        description: example-query description
        required: true
        schema:
          type: string
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/common.StatusMessage'
            application/yaml:
              schema:
                $ref: '#/components/schemas/common.StatusMessage'
        400:
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/common.StatusMessage'
            application/yaml:
              schema:
                $ref: '#/components/schemas/common.StatusMessage'
components:
  schemas:
    common.StatusMessage:
      type: object
      properties:
        message:
          type: string
        status:
          type: string

The .pb may not view properly, access it here . So something like:

�status��
    ��string

looks like:

<0x06>status<0x12><0x0b>
    Ê<0x01><0x06>string

For above example, I first wrote the swagger spec and then generated the .pb but same can be done the other way around.

Current state:

If I have a way to convert between ( .pb ) and ( .proto ) files, the conversion loop will be closed and complete ( .proto -> .pb -> .json/.yaml -> .pb -> .proto ).

I am sure there has to be a way to achieve this, and hence there exists a solution to my original problem. But I could not find any article or piece of code that does it. Are there sane ways to interconvert between .pb and .proto files?

If you have an entirely different solution to my original use-case, please feel free to share that as well. It would help a lot.

Thanks in advance!

Edits:

(1) Thanks to recent comments, it is clear that a "conversion" between .pb and .proto is an absurd ask in the first place. But the original problem remains the same ie how to generate swagger3 (OpenAPI3) spec from protobuf file ( .proto ), either using annotations, tags or otherwise. Changing question title accordingly.

(2) Just the next day after I posted this, I bumped into gnostic-grpc repository, the description of which says:

This tool converts an OpenAPI v3.0 API description into a description of a gRPC service that can be used to implement that API using gRPC-JSON Transcoding.

Again, this got me exited too soon. Actually, this was a GSOC project, and as amazing as the idea of this repository is, it does not fulfill the requirements . Moreover, this is not an interconversion library, and very immature for any production use. In fact, it fails to deliver some of the basic fundamental features of the OpenAPI3 spec.

But this repository is headed in the right direction. My conclusion is to have a custom plugin that does this, mostly by extending the annotations library in GO.

(3) Apparently there are no good and obvious candidates for converting from .proto to OpenAPI3 spec ( .yaml/.json ), except gnostic-grpc which is very immature and highly work in progress for any kind of real use.

But for the reverse conversion, ie OpenAPI3 spec ( .yaml/.json ) to .proto , there is a good library called openapi-generator under OpenAPITools, which converts OpenAPI v2/3 spec to client/server stubs for almost all platforms. But since this is not the original ask, the question still remains open.

Although, your requirement seems to be to get a YAML (OpenAPNv3) specification from a PROTO, you may checkout this plugin - gnostic-grpc - for gnostic which does the reverse ie converts from a YAML/JSON spec to a proto along with gRPC service calls.

We failed to find the direct way to convert .proto file to OpenAPI3/Swagger3. Here is one workaround way

  • convert .proto files to Swagger2 through protoc-gen-openapiv2
  • then convert the Swagger2 files to Swagger3 through this link
    • Swagger Editor
    • Swagger Converter
    • Swagger Codegen version 3.x

Sample

protoc --proto_path=${PROTO_PATH} --swagger_out=logtostderr=true:./swagger.json 

swagger-codegen generate -i ./swagger.json -l openapi-yaml -o swaggerv3.yaml

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM