1 引言

每当项目进入联调阶段,或者提前约定接口时,前后端就会聚在一起热火朝天的讨论起来。可能 99% 的场景都在约定 Http 接口,讨论 URL 是什么,入参是什么,出参是什么。

有的团队前后端接口约定更加高效,后端会拿出接口定义代码,前端会转换成(或自动转成)Typescript 定义文件。

但这些工作都针对于 Http 接口,今天通过 when-to-use-what-rest-graphql-webhooks-grpc 一文,抛开联调时千遍一律的 Http 接口,一起看看接口还可以怎么约定,分别适用于哪些场景,你现在处于哪个场景。

2 概述

本文主要讲了四种接口设计方案,分别是:REST、gRPC、GraphQL、Webhooks,下面分别介绍一下。

REST

REST 也许是最通用,也是最常用的接口设计方案,它是 无状态的,以资源为核心,针对如何操作资源定义了一系列 URL 约定,而操作类型通过 GET POST PUT DELETE 等 HTTP Methods 表示。

REST 基于原生 HTTP 接口,因此改造成本很小,而且其无状态的特性,降低了前后端耦合程度,利于快速迭代。

随着未来发展,REST 可能更适合提供微服务 API。

使用举例:

  1. curl -v -X GET https://api.sandbox.paypal.com/v1/activities/activities?start_time=2012-01-01T00:00:01.000Z&end_time=2014-10-01T23:59:59.999Z&page_size=10 \

  2. -H "Content-Type: application/json" \

  3. -H "Authorization: Bearer Access-Token"

gRPC

gRPC 是对 RPC 的一个新尝试,最大特点是使用 protobufs 语言格式化数据。

RPC 主要用来做服务器之间的方法调用,影响其性能最重要因素就是 序列化/反序列化 效率。RPC 的目的是打造一个高效率、低消耗的服务调用方式,因此比较适合 IOT 等对资源、带宽、性能敏感的场景。而 gRPC 利用 protobufs 进一步提高了序列化速度,降低了数据包大小。

使用举例:

gRPC 主要用于服务之间传输,这里拿 Nodejs 举例:

1.定义接口。由于 gRPC 使用 protobufs,所以接口定义文件就是 helloword.proto

  1. // The greeting service definition.

  2. service Greeter {

  3.  // Sends a greeting

  4.  rpc SayHello (HelloRequest) returns (HelloReply) {}

  5.  // Sends another greeting

  6.  rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}

  7. }

  8. // The request message containing the user's name.

  9. message HelloRequest {

  10.  string name = 1;

  11. }

  12. // The response message containing the greetings

  13. message HelloReply {

  14.  string message = 1;

  15. }

这里定义了服务 Greeter,拥有两个方法: SayHelloSayHelloAgain,通过 message 关键字定义了入参与出参的结构。

事实上利用 protobufs,传输数据时仅传送很少的内容,作为代价,双方都要知道接口定义规则才能序列化/反序列化。

2.定义服务器:

  1. function sayHello(call, callback) {

  2.  callback(null, { message: "Hello " + call.request.name });

  3. }

  4. function sayHelloAgain(call, callback) {

  5.  callback(null, { message: "Hello again, " + call.request.name });

  6. }

  7. function main() {

  8.  var server = new grpc.Server();

  9.  server.addProtoService(hello_proto.Greeter.service, {

  10.    sayHello: sayHello,

  11.    sayHelloAgain: sayHelloAgain

  12.  });

  13.  server.bind("0.0.0.0:50051", grpc.ServerCredentials.createInsecure());

  14.  server.start();

  15. }

我们在 50051 端口支持了 gRPC 服务,并注册了服务 Greeter,并对 sayHello sayHelloAgain 方法做了一些业务处理,并返回给调用方一些数据。

3.定义客户端:

  1. function main() {

  2.  var client = new hello_proto.Greeter(

  3.    "localhost:50051",

  4.    grpc.credentials.createInsecure()

  5.  );

  6.  client.sayHello({ name: "you" }, function(err, response) {

  7.    console.log("Greeting:", response.message);

  8.  });

  9.  client.sayHelloAgain({ name: "you" }, function(err, response) {

  10.    console.log("Greeting:", response.message);

  11.  });

  12. }

可以看到,客户端和服务端同时需要拿到 proto 结构,客户端数据发送也要依赖 proto 包提供的方法,框架会内置做掉序列化/反序列化的工作。

也有一些额外手段将 gRPC 转换为 http 服务,让网页端也享受到其高效、低耗的好处。但是不要忘了,RPC 最常用的场景是 IOT 等硬件领域,网页场景也许不会在乎节省几 KB 的流量。

GraphQL

GraphQL 不是 REST 的替代品,而是另一种交互形式:前端决定后端的返回结果。

GraphQL 带来的最大好处是精简请求响应内容,不会出现冗余字段,前端可以决定后端返回什么数据。但要注意的是,前端的决定权取决于后端支持什么数据,因此 GraphQL 更像是精简了返回值的 REST,而后端接口也可以一次性定义完所有功能,而不需要逐个开发。

再次强调,相比 REST 和 gRPC,GraphQL 是由前端决定返回结果的反模式。

使用举例:

原文推荐参考 GitHub GraphQL API

比如查询某个组织下的成员,REST 风格接口可能是:

  1. curl -v https://api.github.com/orgs/:org/members

含义很明确,但问题是返回结果不明确,必须实际调试才知道。换成等价的 GraphQL 是这样的:

  1. query {

  2.  organization(login: "github") {

  3.    members(first: 100) {

  4.      edges {

  5.        node {

  6.          name

  7.          avatarUrl

  8.        }

  9.      }

  10.    }

  11.  }

  12. }

返回的结果和约定的格式结构一致,且不会有多余的字段:

  1. {

  2.  "data": {

  3.    "organization": {

  4.      "members": {

  5.        "edges": [

  6.          {

  7.            "node": {

  8.              "name": "Chris Wanstrath",

  9.              "avatarUrl": "https://avatars0.githubusercontent.com/u/2?v=4"

  10.            }

  11.          },

  12.          {

  13.            "node": {

  14.              "name": "Justin Palmer",

  15.              "avatarUrl": "https://avatars3.githubusercontent.com/u/25?v=4"

  16.            }

  17.          }

  18.        ]

  19.      }

  20.    }

  21.  }

  22. }

但是能看出来,这样做需要一个系统帮助你写 query,很多框架都提供这个功能,比如 apollo-client。

Webhooks

如果说 GraphQL 颠覆了前后端交互模式,那 Webhooks 可以说是彻头彻尾的反模式了,因为其定义就是,前端不主动发送请求,完全由后端推送。

它最适合解决轮询问题。或者说轮询就是一种妥协的行为,当后端不支持 Webhooks 模式时。

使用举例:

Webhooks 本身也可以由 REST 或者 gRPC 实现,所以就不贴代码了。举个常用例子,比如你的好友发了一条朋友圈,后端将这条消息推送给所有其他好友的客户端,就是 Webhooks 的典型场景。

最后作者给出的结论是,这四个场景各有不同使用场景,无法相互替代:

  • REST:无状态的数据传输结构,适用于通用、快速迭代和标准化语义的场景。

  • gRPC:轻量的传输方式,特殊适合对性能高要求或者环境苛刻的场景,比如 IOT。

  • GraphQL: 请求者可以自定义返回格式,某些程度上可以减少前后端联调成本。

  • Webhooks: 推送服务,主要用于服务器主动更新客户端资源的场景。

3 精读

REST 并非适用所有场景

本文给了我们一个更大的视角看待日常开发中的接口问题,对于奋战在一线的前端同学,接触到 90% 的接口都是非 REST 规则的 Http 接口,能真正落实 REST 的团队其实非常少。这其实暴露了一个重要问题,就是 REST 所带来的好处,在整套业务流程中到底占多大的比重?

不仅接口设计方案的使用要分场景,针对某个接口方案的重要性也要再继续细分:在做一个开放接口的项目,提供 Http 接口给第三方使用,这时必须好好规划接口的语义,所以更容易让大家达成一致使用 REST 约定;而开发一个产品时,其实前后端不关心接口格式是否规范,甚至在开发内网产品时,性能和冗余都不会考虑,效率放在了第一位。所以第一点启示是,不要埋冤当前团队业务为什么没有使用某个更好的接口约定,因为接口约定很可能是业务形态决定的,而不是凭空做技术对比从而决定的。

gRPC 是服务端交互的首选

前端同学转 node 开发时,很喜欢用 Http 方式进行服务器间通讯,但可能会疑惑,为什么公司内部 Java 或者 C++ 写的服务都不提供 Http 方式调用,而是另外一个名字。了解 gRPC 后,可以认识到这些平台都是对 RPC 方式的封装,服务器间通信对性能和延时要求非常高,所以比较适合专门为性能优化的 gRPC 等服务。

GraphQL 需要配套

GraphQL 不是 REST 的替代品,所以不要想着团队从 Http 接口迁移到 GraphQL 就能提升 X% 的开发效率。GraphQL 方案是一种新的前后端交互约定,所以上手成本会比较高,同时,为了方便前端同学拼 query,等于把一部分后端工作量转移给了前端,如果此时没有一个足够好用的平台快速查阅、生成、维护这些定义,开发效率可能不升反降。

总的来说,对外开放 API 或者拥有完整配套的场景,使用 GraphQL 是比较理想的,但对于快速迭代,平台又不够成熟的团队,继续使用标准 Http 接口可以更快完成项目。

Webhooks 解决特殊场景问题

对于第三方平台验权、登陆等 没有前端界面做中转的场景,或者强安全要求的支付场景等,适合用 Webhooks 做数据主动推送。说白了就是在前端无从参与,或者因为前端安全问题不适合参与时,就是 Webhooks 的场景。很显然 Webhooks 也不是 Http 的替代品,不过的确是一种新的前后端交互方式。

对于慢查询等场景,前端普遍使用轮询完成,这和 Socket 相比体验更弱,但无状态的特性反而会降低服务器负担,所以慢查询和即时通讯要区分对待,用户对消息及时性的敏感程度决定了使用哪种方案。

4 总结

最后,上面总结的内容一定还有许多疏漏,欢迎补充。

5 更多讨论

讨论地址是:精读《REST, GraphQL, Webhooks, & gRPC 如何选型》 · Issue #102 · dt-fe/weekly

原文发布时间为:2018-11-03 本文作者:黄子毅

本文来自云栖社区合作伙伴“前端大学”,了解相关信息可以关注“前端大学”。

精读《REST,GraphQL,Webhooks gRPC 如何选型》相关推荐

  1. 【韩松】Deep Gradient Comression_一只神秘的大金毛_新浪博客

    <Deep Gradient Compression> 作者韩松,清华电子系本科,Stanford PhD,深鉴科技联合创始人.主要的研究方向是,神经网络模型压缩以及硬件架构加速. 论文链 ...

  2. 【韩松】Deep Gradient Comression

    <Deep Gradient Compression> 作者韩松,清华电子系本科,Stanford PhD,深鉴科技联合创始人.主要的研究方向是,神经网络模型压缩以及硬件架构加速. 论文链 ...

  3. [文献阅读] Sparsity in Deep Learning: Pruning and growth for efficient inference and training in NN

    文章目录 1. 前言 2. Overview of Sparsity in Deep Learning 2.1 Generalization 2.2 performance and model sto ...

  4. 【翻译】Batch Normalization: Accelerating Deep Network Trainingby Reducing Internal Covariate Shift

    Batch Normalization: Accelerating Deep Network Trainingby Reducing Internal Covariate Shift Sergey I ...

  5. 模型加速--CLIP-Q: Deep Network Compression Learning by In-Parallel Pruning-Quantization

    CLIP-Q: Deep Network Compression Learning by In-Parallel Pruning-Quantization CVPR2018 http://www.sf ...

  6. 论文笔记30 -- (视频压缩)【CVPR2021】FVC: A New Framework towards Deep Video Compression in Feature Space

    <FVC: A New Framework towards Deep Video Compression in Feature Space> CVPR 2021 的一篇Oral 提出了特征 ...

  7. 端到端图像压缩《Asymmetric Gained Deep Image Compression With Continuous Rate Adaptation》

    Asymmetric Gained Deep Image Compression With Continuous Rate Adaptation 一 简介 二 内容 2.1 目前方法的缺陷 2.2 整 ...

  8. 深度学习视频压缩1—DVC: An End-to-end Deep Video Compression Framework

    本文是第一篇端到端使用神经网络来进行视频压缩的论文, github地址:GitHub - GuoLusjtu/DVC: DVC: An End-to-end Deep Video Compressio ...

  9. 【论文阅读】Deep Compositional Captioning: Describing Novel Object Categories without Paired Training Data

    [论文阅读]Deep Compositional Captioning: Describing Novel Object Categories without Paired Training Data ...

  10. CVPR 2018 TRACA:《Context-aware Deep Feature Compression for High-speed Visual Tracking》论文笔记

    理解出错之处望不吝指正. 本文的模型叫做TRACA.模型中使用多个expert auto-encoder,在预训练阶段,每个expert auto-encoder针对一个特定类进行训练:在tracki ...

最新文章

  1. 二进制_Kubernetes集群二进制部署
  2. 逼格高又实用的 Linux 命令,运维同仁一定要懂
  3. python学习手册条件-Python学习手册(第4版)pdf
  4. PAT甲级1122 Hamiltonian Cycle:[C++题解] 图论、模拟
  5. 直接拿来用!最火的Android开源项目(完结篇)(转)
  6. 软件工程进度条-第十二周
  7. antd表格显示分页怎么取消_真相!Word里怎么也删不掉的文档空白页原来是这样...
  8. Python~win32com~Excel
  9. 《成为顶级JAVA架构师的必备书籍》
  10. sql 获取当前之后某天的日期
  11. TensorFlow实现卷积、反卷积和空洞卷积
  12. wps office 2013 利用wps文字制作一张漂亮的座位表
  13. 一年有四季的c语言编程,一年是否有四季?
  14. html项目成员分工合作,科研项目分工如何填写
  15. 史密斯(smith)圆图讲解
  16. 在线答题小程序关于完形填空题的设计
  17. python过京东app图形验证勾股定理_Python爬虫模拟登录京东获取个人信息
  18. 关于算法工程师,你想知道的都在这里!
  19. java 结束循环_java中结束循环的方法
  20. 安装nvm时报错exit status 145和exit status 1 exit status 5

热门文章

  1. 中国在线直播教育行业发展形势与竞争策略研究报告2022-2028年
  2. Go 面向对象编程应用
  3. 单例模式的几种实现方式
  4. 一个略复杂的数据映射聚合例子及代码重构
  5. 当年只会C# 所以写C++就成这样了! log4cplus - log4net
  6. box-sizing:border-box
  7. TCP拥塞控制算法 — CUBIC的补丁(四)
  8. UML建模之业务处理模型(Business Process Model,BPM)
  9. 用nero刻录视频文件的时候不能添加文件
  10. 阿德:工作与发财之间的秘密