FinOps有望降低企业50%+的云成本! 了解详情
写点什么

API 开发者永不“REST”

  • 2020-11-28
  • 本文字数:3046 字

    阅读完需:约 10 分钟

API开发者永不“REST”

免责声明:尽管标题有争议,但本文并不是试图证明 RPC 比 REST 更好,或者 GraphQL 比 RPC 更好。相反,本文的目的是向你介绍这些方法的大致情况以及它们的优缺点。最终的选择将会是一个权衡。


尽管 HTTP 是一个应用层(例如,L7)协议,但在 API 开发方面,HTTP 实际上扮演着一个较低层次的传输机制的角色。


在 HTTP 上如何实现 API 有许多方法,它们在概念上有所不同:

  • REST

  • RPC

  • GraphQL


...但是一个普通的开发人员需要知道的实际清单并不局限于这三个家伙。在这个领域中还有 JSON、gRPC、protobuf 等其它术语。让我们试着一次性了解所有这些术语吧!


代表性状态转移(REST)

首先,REST只是一种软件架构风格。它是一组设计约束,而不是具体的协议。REST 依赖于资源的概念。例如,一个 REST API 是由一组资源(名词)和与这些资源交互的有限数量的动作(动词,查询 fetch、创建 create、更新 update、删除 delete 等)组成。它在思想上非常接近最初的 HTTP 设计,主要基于资源(URLs)和方法(GET、POST、PUT、DELETE)。因此,从实现的角度来看,REST 模型到 HTTP 协议的映射相对简单:


# Create new bookPOST http://myapi.com/books/ (author="R. Feynman", year=1975) -> book_id
# Get book with ID = 1GET http://myapi.com/books/1 () -> (id=1, author="R. Feynman", year=1975)
# Update book with ID = 1PUT http://myapi.com/books/1 (id=1, author="Richard Feynman", year=1975) -> (...)
# Delete book with ID = 1DELETE http://myapi.com/books/1 () -> nu
复制代码


可能每一个现代 web 框架都提供了构建一个 REST 风格的 Web 服务所需的所有现成工具。从客户端的角度来看,调用一个 REST API 非常简单——它只需要将指定的 HTTP 方法发送到一组预定义的 URLs。


然而,从 API 设计者的角度来看,如何用资源术语(即名词)表示现实世界的领域并保持有限数量的动作(即动词)是并不明显的。令人惊讶的是,尽管 REST 一次在当今被广泛使用,但被认为是真正的 REST 风格的现代 API 并不多。在设计 REST 风格的 Web 服务时坚持纯粹,或导致 API 设计非常笨重。

远程过程调用(RPC)

同样,RPC也是一种 API 设计技术。RPC 聚焦于动作(动词)概念,这通常使得涉及到的资源(名词)非常原始和特别。对于业务模型中的每个过程或事务,API 设计者只需要添加一个 RPC 端点:


# Create new bookcreateBook(author, year) -> book_id
# Get book by IDgetBook(book_id) -> book
# Change book's authorsetBookAuthor(book_id, author) -> null
# Delete book by IDdeleteBook(book_id) -> nu
复制代码


在幕后,应该有另外一层将这样的过程调用映射到 HTTP 请求。例如,setBookAuthor(1, "Richard Feynman")会被这样映射:


<span role="presentation" style="box-sizing: border-box; padding-right: 0.1px;">POST http://myapi.com/set-book-author/ (book_id=1, author="Richard Feynman") -> null</span role="presentation" style="box-sizing: border-box; padding-right: 0.1px;">
复制代码


现在,让我们比较一下 REST 和 RPC 中改变作者姓名的任务。虽然在 RPC 中的实现看起来比较简单,但在 REST 风格的实现中有许多有争议性的问题需要回答。如果作者的名字是 book 的一个属性,那么我们是否应该在发送PUT /books/1 时,提供一个包含修改过的作者字段的完整的 book 对象?如果客户端没有完全的 book 对象怎么办?我们应该先获取 book 对象,还是只传送 book ID 和新的作者名字?但是服务端的其它属性怎么办?如果一个几乎空白的PUT 请求到达,它们是否应该归零(这将是灾难性的,但是与 REST 原则的决定一致)?或者我们应该放弃 HTTPPUT 方法,开始使用PATCH 方法(你听说过这个方法吗)?


幸运的是,如果我们遵循 RPC 方案,我们可以简单忽略上面这些问题。但是,当然也有一个缺点——一个典型的 RPC API 通常包含大量的自定义过程。显然,这使得 RPC 模型到 HTTP 层的映射是一个不平凡的任务。好在 API 设计者很少需要考虑这一部分。有很多库在 HTTP 上实现了 RPC 层,其中一些库非常杰出(是的,我说的是谷歌的 gRPC 和脸书的 Thrift)。但是 RPC 方案还有一个更复杂的问题...


一打丰富的 REST 资源结合 3-5 个 HTTP 方法通常可以覆盖一百个用例。REST API 故意为领域模型引入了一个常规结构,使其增长和演化更加可控。相反,RPC APIs 是自然增长的。引入一个新的用例通常需要在已经膨胀的列表中再增加几个 API 端点。由于 API 设计没有强制面向实体的结构,因此在相对短的时间内,RPC 调用的数量可能会超过一个团队可以处理的最大复杂度。

GraphQL

现在,,我们已经知道 RPC 和 REST 方案都不理想。REST 存在过度和欠缺查询问题,可能会导致在设计阶段的比较耗神。但是如果我们尝试用一百个特别的 RPC 端点来取代面向实体的设计,随着时间的推移,维护过度增长的 RPC API 会是一个噩梦。


GraphQL试图解决这两种技术的弱点。假设面向实体的领域模型有助于开发人员长期安心,GraphQL 方案从定义模板开始,例如资源集(即名词)和它们的关联关系。听起来很像一张图,不是吗?有了正式的模板定义,GraphQL 在其上构建了一个相当复杂的服务器和客户端。厚客户端允许查询(QL 代表 query language,即查询语言)自定义的和组合的资源。厚服务器知道如何根据客户端的查询和领域模板来填充响应。


因此,GraphQL API 基本上由一个端点组成。即,没有臃肿的 API 了。同时,它超级灵活和可以定制的查询有助于避免从服务器查询不必要的数据。此外,开发人员仍然可以从正式的面向实体的领域模板中受益。但是凡事总是有代价的。这里的代价是 GraphQL 客户端和服务器端的极度复杂性。所以,是的,一切都关乎取舍...

protobuf、JSON 等怎么样?

活动部分的适当分类能够有助于你将注意力集中在 API 开发领域。现在,我们已经知道 REST 和 RPC 仅仅只是架构风格。而 GraphQL,我倾向于认为它也是一种风格,即使从技术上来讲它是一种由运行时支持的正式语言。


但是,如果 GraphQL 是由一个特定实现支持的,那么我们可能期望 RPC 和 REST 也有相同的实现支持。事实上,确实有很多著名的 RPC 框架——gRPCApache ThriftApache Avro等等。令人惊讶的是,REST 框架中似乎没有明显的领导者。可能是因为 REST 在技术上非常接近 HTTP,而且几乎每个 Web 框架都已经很好地支持了它。


嗯,但是protobuf怎么样?显然,它只是数据在通过网络被发送或存储到某个地方之前对其进行序列化的方法之一。gRPC 是一个特殊的 RPC 框架,完全依赖 protobuf。而且由于这两个技术通常是一起使用的,而且被一起发布,因此很多人都将 gRPC 和 protobuf 交互使用。然而,在你的REST风格的API中使用protobuf也非常不错protobuf 可以用作一种编码格式,我们目前在工作中对我们的一些服务就是这么做的。因此,protobuf 不应该与 REST 或 RPC 框架一起比较,而是可以与 XML JSON 一起比较。


更让你困惑的是,Apache Thrift 有它自己的序列化格式,称作 Thrift!即,gRPC 使用 protobuf 编码格式,而 Thrift 使用 Thrift 编码格式🙈


总之,设计一个 HTTP API 有许多不同的架构风格。其中最流行的三种是 REST、RPC 和 GraphQL。每一种风格都可以用很多种方法实现,而且有很多著名的框架,例如 gRPC 和 Apache Thrift。在底层,它们依赖更低级别的机制,如数据序列化(protobuf、JSON、XML)或协议(JSON-RPC、 XML-RPC)。而且较低级别的代码有时会在不同的风格之间复用,这使得整个 API 开发领域乍一看都非常复杂。


作者介绍

Ivan Velichko 是一名涉及很多领域且具有 10 年实践经验的软件工程师;热衷于可靠性和分布式系统。软件开发不仅是专业还是爱好。最有意义的活动是增加对复杂系统的理解。


原文链接:API Developers Never REST

2020-11-28 10:571318

评论

发布
暂无评论
发现更多内容

架构实战营 毕业总结

竹林七贤

某宝付费的Redis核心原理深度实践PDF,竟在GitHub标星86k+霸榜

白亦杨

Java 编程 程序员 架构师 计算机

深入了解Spring之Environment

邱学喆

Profile Environment PropertySource PropertySources

Tensorflow for Java + Spark-Scala分布式机器学习计算框架的应用实践

Qunar技术沙龙

机器学习 tensorflow spark 后端 分布式计算

学生管理系统详细架构设计文档

张文龙

#架构实战营

"开放数据,蔚然成林"—浪潮助力多地获得数据开放全国标杆

浪潮云

云计算

15年前的3篇论文,变成了万亿大生意

百度大脑

人工智能 论文

墙裂推荐!四面阿里拿 offer 后,才发现师哥给的面试笔记有多强大

Java 架构 IT 计算机 知识

CODING 携手 CoDesign:让设计与开发更简单

CODING DevOps

DevOps 设计 开发工具 CoDesign

一种Vue应用程序错误/异常处理机制

devpoint

Vue 异常处理 vue2 7月日更

架构训练营 模块三

小卷儿

使用MLlib进行机器学习(十-下)

数据与智能

spark 决策树 优化

为什么双赞安卓ARM工控主板应用前景那么好?

双赞工控

完善数字人民币发行应用机制 打造可靠金融基础设施

CECBC

阿里 P8 熬了一个月肝出这份 32W 字 Java 面试手册,在 Github 标星 31K+

Java 编程 架构 面试 IT

偶获阿里大佬纯手码“887”页 Java 面试手册,突击学习一个月,成功跳槽阿里!

Java 编程 架构 面试 IT

PancakeSwap交易所做市机器人|交易所画K线机器人

Geek_23f0c3

交易所机器人 pancakeswap 做市机器人

加码物联网安全,熵核科技做终端安全的守护者

熵核科技

spring,springboot,底层原理解析

java小李

仅仅上线一小时,下载量就破10W!阿里内部Java性能优化实战手册

Java 编程 程序员 面试 IT

粉了!京东商城核心亿级流量并发Java系统架构设计方案手册

Java架构追梦

Java 架构 面试 高并发 京东

Java版人脸检测详解上篇:运行环境的Docker镜像(CentOS+JDK+OpenCV)

编程菌

Java 编程 程序员 后端 java技术宅

应届女生美团Java岗4面,一次性斩offfer,我受到了万点暴击

编程菌

程序员 面试 后端 计算机

Vue进阶(三):Axios 应用详解

No Silver Bullet

Vue axios 7月日更

祝贺中国跳水队夺金!百度智能云挺敢做梦的人

百度大脑

人工智能 跳水队

极致性能一睹为快!阿里全新出品性能优化手册 从此拒绝系统瘫痪!

Java 编程 程序员 架构师 计算机

从简历被拒到收割 9 个大厂 offer,我用了 3 个月成功破茧成蝶

Java 编程 程序员 架构 计算机

关于体验设计的十大重要定律

石云升

读书笔记 用户体验 商业洞察 7月日更 体验设计

都2021年了,还在问网络安全怎么入门,气得我当场脑血栓发作

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 安全漏洞

基于深度学习的实时噪声抑制——深度学习落地移动端的范例

声网

人工智能 算法 移动端

CRUD 程序员勿进!JDK源码剖析手册与并发编程图册,完美诠释高并发

Java 编程 程序员 IT 计算机

  • 需要帮助,请添加网站小助手,进入 InfoQ 技术交流群
API开发者永不“REST”_语言 & 开发_Ivan Velichko_InfoQ精选文章