我的原始用例:
我正在使用gRPC
服务器(使用protobuf
)构建GO应用程序,并将其包装在HTTPS服务器(使用gin
)中。仅HTTPS服务器被发布供客户使用(我的意思是,我的应用程序可以通过REST API访问,实际上然后拨号gRPC端点),并且我使用Swagger
OpenAPI3(版本3是主要要求)规范进行发布。需要gRPC和HTTPS,任何解决方案都应符合这种架构。
我不想在两个位置维护我的服务器规范,也就是说,我不想维护proto文件(.proto
)和swagger规范(.json/.yaml
)。由于我必须编写proto文件来生成gRPC服务器,因此我希望自动化生成swagger规范(OpenAPI3)。
我的进展情况:
我能够使用grpc-gateway库从protobuf文件(.proto
)生成swagger
OpenAPI2规范,类似于grpc-rest-go-example。但是我的要求是OpenAPI3;更具体地说,我想使用OpenAPI3中的oneOf
功能,并从proto的oneof
特性进行映射。这在OpenAPI2中不可能,因为它不允许API具有多个类型定义的请求/响应正文,这是通过启用oneOf、anyOf和allOf结构在OpenAPI3中添加的一项功能。
在尝试这样做时,我偶然发现了GoogleAPIs的googleapis/gnostic库,它的描述是:
此存储库包含一个Go命令行工具,该工具可以将JSON和YAML OpenAPI描述转换为等效的Protocol Buffer表示形式,并从中间进行转换。
乍一看,这似乎完全解决了我的问题,但事实证明,此库仅在协议缓冲区(protobuf)二进制文件(.pb
)和swagger OpenAPI2/OpenAPI3(.json/.yaml
)文件之间进行互相转换,这使我遇到了新问题。
例如,对于以下.pb
文件:
�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
它会生成以下Swagger文件:
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
如果
.pb
文件无法正常查看,请前往这里。因此可以像这样处理:
�status��
��string
看起来像:
<0x06>status<0x12><0x0b>
Ê<0x01><0x06>string
对于上述例子,我先编写了Swagger规范,然后生成了.pb
,但也可以反过来做同样的事情。当前状态:
如果我有一种方法在(.pb
)和(.proto
)文件之间进行转换,那么转换循环将被关闭并完成(.proto
-> .pb
-> .json/.yaml
-> .pb
-> .proto
)。
我确定必须有一种方法实现这一点,因此存在解决我的原始问题的解决方案。 但是我找不到任何可以实现它的文章或代码片段。 是否有理智的方法在.pb
和.proto
文件之间互相转换?
如果您对我的原始用例有完全不同的解决方案,请随意分享。 这将非常有帮助。
提前致谢!
编辑:
(1)由于最近的评论,很明显首先在.pb
和.proto
之间进行“转换”是一个荒谬的要求。 但是原始问题仍然相同,即如何从protobuf文件(.proto
)生成swagger3(OpenAPI3)规范,无论是使用注释,标签还是其他方式。 相应地更改问题标题。
(2)就在我发布这篇文章的第二天,我遇到了gnostic-grpc存储库,其中的描述说:
此工具将OpenAPI v3.0 API描述转换为可以用于实现该API的gRPC服务的描述,并使用gRPC-JSON Transcoding。
再次,这让我非常兴奋。 实际上,这是一个GSOC项目,尽管这个存储库的想法如此惊人,但它不能满足要求。 此外,这不是一个互相转换的库,对于任何生产使用都非常不成熟。 实际上,它未能提供OpenAPI3规范的一些基本基本功能。
但是这个仓库朝着正确的方向前进。 我的结论是使用自定义插件完成这项工作,主要是通过扩展GO中的注释库来完成。
(3)显然没有很好的候选项可以从.proto
转换为OpenAPI3规范(.yaml/.json
),除了gnostic-grpc之外,该存储库非常不成熟并高度工作正在进行中,适用于任何实际用途。
但是对于相反的转换,即OpenAPI3规范(.yaml/.json
)到.proto
,有一个名为openapi-generator的良好库在OpenAPITools下,它将OpenAPI v2 / 3规范转换为几乎所有平台的客户端/服务器存根。 但由于这不是最初的要求,问题仍然悬而未决。