跨语言接口强约束有没有什么好方案?除了 google probuf 之外

2021-09-18 11:17:08 +08:00
 abcbuzhiming
和别人交流时了解到了一种做法:他们使用 grpc 来约束服务之间互相调用的接口,protocol 文件单独写在一个 git 仓库里,其它的项目都引用这个项目作为子模块,编译后生成对应语言的调用接口和数据结构。这样接口定义就能同时约束客户端和服务器,因为是强类型约束,一旦接口数据结构变动就会通过 protocol 文件让客户端和服务器都感知到。

这个“能够跨语言让客户端和服务器之间的数据交互被强约束”思路我个人是很认同的,平时开发时也经常遭遇服务端改了数据却忘记通知客户端的问题。

但是我进一步观察后认为为了用 protocol 文件,而上 grpc 是不值得,grpc 的联调非常麻烦远不如 rest api,我明明只是想用数据强约束,但是 grpc 并非是我必须的。本质上我们互相传来传去的也不过是一段 json 而已。

那么有更好的办法能实现这种服务端和客户端之间互相能够感知到改变的数据接口强约束吗? json 就没有解决方案吗?另外 GraphQL 就不要谈了,这东西的成本比 grpc 还高,中小型公司你还能看到 GRPC,GraphQL 我只在大公司就认搞过。目前还是希望能够继续得到 REST API 使用和调试的遍历性
3635 次点击
所在节点    程序员
22 条回复
murmur
2021-09-18 11:17:38 +08:00
现在的人都忘了 xml 么
Itoktsnhc
2021-09-18 11:29:13 +08:00
主要就是共享 api 的定义嘛。要不 grpc 这种共享子模块,要不就有个 api 定义 ,然后有个 generator 生成 dto/entity,swagger 这种,然后考虑怎么自动化这个过程。

另外野路子就是 F# 的 TypeProvider,直接给你把各种定义在 coding 阶段给你动态的生成出来强类型。api 变了编译都过不去,还有很好用的智能提示。TypeProvider 可以为 CSV,db,甚至 CSS 这种,强类型的 CSS 怕不怕
gam2046
2021-09-18 11:37:41 +08:00
protobuf 和 grpc 并不强制绑定,可以单独使用 protobuf,另一个是 grpc 调试也不麻烦,可能是你相对来说没那么熟悉,刚开始有那么一个过程
abcbuzhiming
2021-09-18 11:46:09 +08:00
@murmur 怎么用 xml 生成跨语言的接口数据结构定义?不是直接用 xml 传递
abcbuzhiming
2021-09-18 11:47:01 +08:00
@Itoktsnhc 对,就是要考虑自动生成 dto/entity,swagger 这种,现在就是没有好办法自动化
abcbuzhiming
2021-09-18 11:48:46 +08:00
@gam2046 grpc 再不麻烦也比 REST Http 麻烦,这东西就是怕比。protobuf 直接通过编译生成接口和数据定义的方式我没找到,既有的手段都是依赖 grpc 本身的。
aristolochic
2021-09-18 11:54:11 +08:00
grpc 主要是 protobuf 它就不是一个透明的序列化协议,为了性能和紧凑必须要定义 proto 文件,这不是顺便就解决了约束吗?另外也就有底气支持更加复杂的类型。而且这个约束还必须要遵守,如果不知道 proto 文件就是一坨二进制数据根本没法解析。而透明的序列化协议就压根不需要事先协商,不管谁传过来的都能直接用。这类序列化协议不一定非得是文本格式,msgpack 就是二进制版的 JSON 也可以直接用。也不是没有约束的方法,这个约束我们一般称为 Schema

要是说 Schema 的话,最先想到的估计就是 SGML/HTML/XML 那家子,从一开始就设计了 DocType 还有 Schema 。这些都是官方实现,用了好多年了相当成熟

但是也不是说 JSON 就没有了。JSON Schema 咋说也够用,还能提供更多的约束,要求更高还能自定义原语。比如上面提到的 Swagger 设计的 OpenAPI 3 spec 就是 JSON Schema 改的,不过定义了自己的原语实现更多约束,还重新诠释了 JSON Schema 规范中的一些字段(我是不太喜欢这么搞的,一下子就不兼容了

要是嫌 JSON Schema 不是官方 RFC 出的,那就次一点用 JSON Type Definition 。这个就没有更多的约束了,不过对于类型本身应该是比 JSON Schema 更细化,你想要指定 int 位数、有没有符号都行,而且还有一个 JSON Schema 里实现起来比较别扭的,就算不别扭也不一致,就是它能用 Discriminator 实现 Tagged Union / Sum Type

要说类型生成器,JSON Schema 和 JSON Type Definition 都有不少。如果是 JavaScript 这种动态类型的也可以用流式 API 定义 JSON Schema 。XML 的 Schema 就更别说了,理应是更加成熟

(话说 ML/类 ML 语言社区搞的类型系统应用都挺魔怔的,印象里 Haskell 的 Yesod 有 CSS 、HTML 和 URL 等等等等的强类型。现在看来也不是只有 Haskell 这么狠
Hconk
2021-09-18 12:46:25 +08:00
有个叫 gSOAP 的东西可以看看。
masterclock
2021-09-18 13:16:32 +08:00
protobuf 不一定要 grpc,序列化后串口传输都干过
grpc 也不一定要 protobuf,用过 JSON 序列化的 grpc
总的来说,grpc 挺好用的,protobuf 有很多奇怪的缺点
SingeeKing
2021-09-18 13:22:53 +08:00
非要这么干,protobuf 定义 entity,protobuf 是有 canonical json 实现的,所以可以基于 REST 传输,跨语言什么的也都没问题

—— 然而有什么意义呢,还不如直接上 grpc,生态很完善,联调其实并不麻烦
SingeeKing
2021-09-18 13:24:26 +08:00
「 protobuf 直接通过编译生成接口和数据定义的方式我没找到,既有的手段都是依赖 grpc 本身的。」???

https://developers.google.com/protocol-buffers/docs/javatutorial#compiling-your-protocol-buffers
wangbenjun5
2021-09-18 13:29:43 +08:00
人家用 protobuf 是为了节省资源消耗,加快服务响应速度,你为了约束接口?难道 http json 这种方式就不能约束了吗?我接口文档甩你,你按文档来就行了,如果文档和实际接口不一致那就是接口负责人的问题。
lonenol
2021-09-18 13:41:26 +08:00
自己做一个开放平台,在开放平台定义接口和数据结构,两边分别实现自己的逻辑。。。
joesonw
2021-09-18 14:06:35 +08:00
swagger/openapi 是 http 的
dk7952638
2021-09-18 14:24:22 +08:00
rest 天生就不适合处理复杂的关系
ipwx
2021-09-18 15:28:39 +08:00
JSON 自己捏一套

我就自己捏了一套,满足 JSON + C++
ipwx
2021-09-18 15:28:48 +08:00
满足 Python + C++
Wanyne
2021-09-18 23:34:12 +08:00
grpc-gateway,grpc 转 rest 接口,同时支持 grpc 和 rest api
zartouch
2021-09-19 15:09:44 +08:00
json 的话 openapi 应对的 json 也可以做到啊。这个说白了就是 schema 校验么。

还有“ 一旦接口数据结构变动就会通过 protocol 文件让客户端和服务器都感知到” 这个其实是是需要客户端升级 api 版本才能做到的。何况有的变动是没法通过 schema 感知的,比如你的 date 是 string 格式从 yyyymmdd 改成了 yyyy-MM-dd 这个错误并不会在编译时报错。所以设计的 api 实际上肯定会向后兼容,breaking change 都会是新的 api 版本会直接在 rest api path 上面体现出来。否则就是设计的 api 本身的问题
IvanLi127
2021-09-20 01:38:01 +08:00
graphql ?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/802723

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX