grpc-gateway 怎么在 OpenAPI 响应的 schema 中引用任意消息?
【免费下载链接】grpc-gatewaygRPC to JSON proxy generator following the gRPC HTTP spec项目地址: https://gitcode.com/GitHub_Trending/gr/grpc-gateway
当你用 grpc-gateway 的protoc-gen-openapiv2插件生成 OpenAPI(Swagger)文档时,每个 RPC 的响应 schema 默认取自该 RPC 的返回类型。如果你的接口需要返回一个与返回类型不同的统一结构——比如一个错误消息、一个枚举、或者其他文件里定义的消息——就需要在响应描述里通过ref引用任意消息。本文基于仓库文档 Using arbitrary messages in response description 说明具体做法:在 proto 选项里给响应加一个schema.json_schema.ref,生成后 OpenAPI 文档中该响应的 schema 就会变成指向目标消息定义的$ref。
前提条件
- 你的 proto 文件要使用
protoc-gen-openapiv2的自定义注解,即已经import "protoc-gen-openapiv2/options/annotations.proto";(该导入同时提供openapiv2_swagger、openapiv2_operation等选项定义,见 annotations.proto)。 - 已具备生成环境。按 README 的说明:使用
buf时,把buf.build/grpc-ecosystem/grpc-gateway加入buf.yaml的deps;使用protoc时,需要把本仓库protoc-gen-openapiv2/options目录下的 protobuf 文件拷贝到你自己的 proto 目录树中,并让protoc能在-I路径里找到它们。
在文件级响应中通过 ref 引用消息
以一个结构为例(取自文档示例):
syntax = "proto3"; package example.service.v1; import "protoc-gen-openapiv2/options/annotations.proto"; service GenericService { rpc GenericRPC(GenericRPCRequest) returns (GenericRPCResponse); } message GenericRPCRequest { string id = 1; } message GenericRPCResponse { string result = 1; }如果想让该 proto 文件里所有 RPC的 OpenAPI 响应都包含一个自定义响应(例如 400),在文件上追加openapiv2_swagger选项,并定义好被引用的消息:
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { responses: { key: "400" value: { description: "Returned when the request is malformed." schema: { json_schema: {ref: ".example.service.v1.GenericResponse"} // Must match the fully qualified name of the message } } } }; message GenericResponse { repeated string resources = 1; repeated string errors = 2; }ref的取值规则以 openapiv2.proto 中JSONSchema.ref字段的注释为准:
- 它可以是一个全限定的 proto 消息名(带前导点,包含完整 package),如文档示例中的
.example.service.v1.GenericResponse,或.google.protobuf.Timestamp; - 被引用的类型必须 import 进当前 proto 文件("that type must be imported into the protofile");
- 如果
ref指向的识别不出对应消息,该 Ref 会原样写进生成结果("the Ref will be used verbatim in the output")。
只对单个 RPC 生效时的写法
文档指出 "The annotation can also be specified per-rpc"。按 RPC 生效时,使用 annotations.proto 中扩展google.protobuf.MethodOptions的openapiv2_operation选项,它带有与文件级相同的responsesmap(结构见 openapiv2.proto 中的Operation消息)。写法与文件级一致,只是把responses块移到具体 rpc 的option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation)里。
如果你的 proto 无法修改(例如第三方服务),OpenAPI 选项还可以放在外部 YAML 配置文件中,通过openapi_configuration参数传入;gRPC API Configuration 文档 给出了该用法与 unannotated_echo_service.swagger.yaml 这个示例文件(其中展示了 file/method 两级responses的 YAML 结构)。
生成并验证结果
用protoc生成 OpenAPI 文件(命令取自 README):
protoc -I . --openapiv2_out ./gen/openapiv2 \ your/service/v1/your_service.proto使用buf时则在buf.gen.yaml中加入protoc-gen-openapiv2插件后执行buf generate。
生成后打开产出的*.swagger.json,验证点有两个:
- 对应 operation 的
responses中出现你配置的响应码,其 schema 为$ref。文档给出的示例输出(文档示例,包名不同会得到不同名字)是:
"400": { "description": "Returned when the request is malformed.", "schema": { "$ref": "#/definitions/v1GenericResponse" } },- 文档顶部的
definitions段中包含被引用消息的完整 schema 定义,$ref指向的就是该定义名。
仓库自身的示例可以作为一个可核对的参照:a_bit_of_everything.proto 中用json_schema: {ref: ".grpc.gateway.examples.internal.proto.examplepb.ErrorResponse"}配置了 500 响应,其生成产物 a_bit_of_everything.swagger.json 里对应出现"$ref": "#/definitions/examplepbErrorResponse",同一文件中的 418 响应引用枚举后生成了"$ref": "#/definitions/examplepbNumericEnum"。注意$ref里的定义名是由消息的完全限定名推导出来的(文档示例中 package 为example.service.v1时生成v1GenericResponse),不要手动写定义名,以ref中填写的完全限定名为准。
限制与边界
- 文件级的
responses作用于该 proto 文件定义的所有 RPC;只对个别方法生效要用 per-rpc 的openapiv2_operation选项。 ref不是任意的 JSON 字符串占位:填的是全限定消息名且消息已 import 时,才会被解析为指向 definitions 的$ref;填了但识别不出消息时会被原样输出,需要回到 proto 检查包名和 import。- 该机制用于
protoc-gen-openapiv2(OpenAPI v2)的生成路径;本文不覆盖protoc-gen-openapiv3的输出格式差异,两者各自的选项定义分别位于 protoc-gen-openapiv2/options/ 与 protoc-gen-openapiv3/options/。
【免费下载链接】grpc-gatewaygRPC to JSON proxy generator following the gRPC HTTP spec项目地址: https://gitcode.com/GitHub_Trending/gr/grpc-gateway
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考