V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
abcbuzhiming
V2EX  ›  程序员

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

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

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

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

    那么有更好的办法能实现这种服务端和客户端之间互相能够感知到改变的数据接口强约束吗? json 就没有解决方案吗?另外 GraphQL 就不要谈了,这东西的成本比 grpc 还高,中小型公司你还能看到 GRPC,GraphQL 我只在大公司就认搞过。目前还是希望能够继续得到 REST API 使用和调试的遍历性
    22 条回复    2021-09-22 10:20:54 +08:00
    murmur
        1
    murmur  
       2021-09-18 11:17:38 +08:00
    现在的人都忘了 xml 么
    Itoktsnhc
        2
    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
        3
    gam2046  
       2021-09-18 11:37:41 +08:00
    protobuf 和 grpc 并不强制绑定,可以单独使用 protobuf,另一个是 grpc 调试也不麻烦,可能是你相对来说没那么熟悉,刚开始有那么一个过程
    abcbuzhiming
        4
    abcbuzhiming  
    OP
       2021-09-18 11:46:09 +08:00
    @murmur 怎么用 xml 生成跨语言的接口数据结构定义?不是直接用 xml 传递
    abcbuzhiming
        5
    abcbuzhiming  
    OP
       2021-09-18 11:47:01 +08:00
    @Itoktsnhc 对,就是要考虑自动生成 dto/entity,swagger 这种,现在就是没有好办法自动化
    abcbuzhiming
        6
    abcbuzhiming  
    OP
       2021-09-18 11:48:46 +08:00
    @gam2046 grpc 再不麻烦也比 REST Http 麻烦,这东西就是怕比。protobuf 直接通过编译生成接口和数据定义的方式我没找到,既有的手段都是依赖 grpc 本身的。
    aristolochic
        7
    aristolochic  
       2021-09-18 11:54:11 +08:00   ❤️ 2
    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
        8
    Hconk  
       2021-09-18 12:46:25 +08:00 via iPhone
    有个叫 gSOAP 的东西可以看看。
    masterclock
        9
    masterclock  
       2021-09-18 13:16:32 +08:00
    protobuf 不一定要 grpc,序列化后串口传输都干过
    grpc 也不一定要 protobuf,用过 JSON 序列化的 grpc
    总的来说,grpc 挺好用的,protobuf 有很多奇怪的缺点
    SingeeKing
        10
    SingeeKing  
       2021-09-18 13:22:53 +08:00
    非要这么干,protobuf 定义 entity,protobuf 是有 canonical json 实现的,所以可以基于 REST 传输,跨语言什么的也都没问题

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

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

    我就自己捏了一套,满足 JSON + C++
    ipwx
        17
    ipwx  
       2021-09-18 15:28:48 +08:00
    满足 Python + C++
    Wanyne
        18
    Wanyne  
       2021-09-18 23:34:12 +08:00
    grpc-gateway,grpc 转 rest 接口,同时支持 grpc 和 rest api
    zartouch
        19
    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
        20
    IvanLi127  
       2021-09-20 01:38:01 +08:00 via Android
    graphql ?
    changwei
        21
    changwei  
       2021-09-21 02:11:53 +08:00
    openapi 了解一下,3GPP 等技术标准化组织都是使用 openapi ymal 格式发布接口定义的,具体可以参考 ftp://www.3gpp.org/Specs/archive/29_series/29.551/OpenAPI/2018-12
    SmiteChow
        22
    SmiteChow  
       2021-09-22 10:20:54 +08:00
    看你描述核心就是想要 S-C 接口同步升级,和编程实现流程没关系,最简单的就是按照 RESTFull 规范升级资源版本号=>/api/v1.0.0/user 且不兼容旧版本接口
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4548 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 01:06 · PVG 09:06 · LAX 17:06 · JFK 20:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.