[译] 将现有的 API 从 REST 迁移到 GraphQL

本文讲的是[译] 将现有的 API 从 REST 迁移到 GraphQL,


将现有的 API 从 REST 迁移到 GraphQL

最近的六个月内我发现几乎每一场有关于 Web 开发的大会都谈论到了 GraphQL。也有大量与其相关的文章被发表。但是所有的这些几乎都是在讲 GraphQL 的基础概念或者是新特性,说得很表面。因此我打算谈谈我在真实大型系统中采用 GraphQL 的个人经验。

REST 有什么问题

REST(一如 SOAP)没有分离传输、安全和数据逻辑层面。这会带来很多问题。让我们来看看其中的几个。

GET 查询能力的低下

用 GET 语句进行复杂深入的查询是不可能的。假设我们需要查询用户。举一个很简单的例子:

GET /users/?name=Homer

然后想象一下,我们需要查找名字是 Homer 或者 Marge 的用户。事情就变得有点棘手了。当然,我们可以为这种需求定义一些分隔符。

GET /users/?name=Homer|Marge

但是,不要忘记转义这些字符!并且牢记,如果有人的名字中包含 “|” 那么你就完蛋啦。如果要结合两个不同的字段那么就更复杂了。更别说是需要同时满足上面两种条件的查询。

目前我们一般都是使用字段来查询对应的内容。但是也时常需要用查询语句来传递一些服务数据。比如页码:

GET /users/?name=Homer|Marge&limit=10&offset=20

按逻辑来说,我们后端的查询解析器应该会将 limit 和 offset 识别为数据库的字段,因为他们被声明为和 “name” 字段同级的参数名。

我们可以发明我们自己的语法或是用 POST 方法(这是不对的,因为这是一个幂等请求)但是这看起来像是在造轮子。

数据更新的问题

使用 PUT 发送整个对象是最简单的 REST 更新数据的方式。但显而易见的是,当你仅仅只需要更新 1 Mb 大小的对象中的一个字段时,这并不是最有效的方式。

HTTP 还有一个 PATCH 方法。但是它有一个问题。用算法来定义 如何更新实体 并不简单。现有多个规范建议你应该如何去做,比如 RFC 6902,RFC 7396 以及许多自定义解决方案。

命名问题

我猜测每个曾与 REST 打交道的开发者都明白这种感受,当你不知道如何去命名你的新路由时。并非所有的业务实例都可以被描述为资源。例如我们想要搜索带有商店信息的商品。

GET /search?product_name=IPhone&shop_name=IStore

这里的资源是什么?商品?商店?搜索?

天哪,我的 API 不再是 REST 风格了!

另一个典型的例子便是用户登录。这里的资源又是什么?Spoiler:这里没有资源,这里只是个远程过程调用而已。

后端处理 REST

app.post((req, res) => {
  const user = db.getUserByName(req.headers.name);
  const user = db.getUserByName(req.query.name);
  const user = db.getUserByName(req.path.name);
  const user = db.getUserByName(req.body.name);
});

这是一个 Express 路由的例子。这里我们试图获取用户的 ID 来查找用户。让我们看一看 API 函数通常应该是什么样子:



函数接收参数,进行特定的处理并返回特定的结果。

在这个 Express 路由的例子中我们的参数是什么?一个巨大杂乱的 req 对象,而我们仅需要其中很小的一部分数据。

当然,这也是 Express 的一个问题(准确的说是 Node 的 HTTP 模块的问题),但是这样的接口也是因为 HTTP 的实现逐步进化而产生的 - 请求参数可以在任何位置,所以如果你本人不知道它或者没有使用描述良好的文档时想要准确知道参数位置是不可能的。

这就是为什么使用没有接口文档的 REST 是如此的痛苦。

GraphQL

在这里我们假设你早就熟悉 GraphQL 的基础知识。如果没有,你可以从 Apollo 写的关于GraphQL 基础知识的介绍开始。

正如我们前面所展示的,REST 存在一些 GraphQL 所没有的设计上的问题。并且 GraphQL 有着巨大的发展潜力。

首先 GraphQL 提供 RPC 访问方式,这意味着你将不受客户端-服务端的交互限制。GraphQL 有它自己的类型系统,这意味不再有令人误解的错误和漏洞。并且类型系统意味着你的客户端可以提供 item 级别的数据智能缓存。还拥有大量像是网络连接(游标和分页)、批处理、延时等的面向 Web 的特性。它 使你的客户端-服务端交互尽可能的高效。

但是 REST 仍然是业内标准

是的,无论我们是否喜欢,REST 都是近几年 API 的主流形式。

但是我们仍然可以为一些内部需求(比如对接一些高级客户端)去使用 GraphQL,其他的使用 REST。

为此,我们需要将 REST 路径包装成 GraphQL 类型。这里有一些文章和例子(被提到最多的是 swapi-rest-graphql)关于从 REST 迁移到 GraphQL。但是它们建议使用自定义解析器,这无法满足拥有成百上千路径的大型项目。

在我最近的三个项目中我使用 Swagger 来描述 REST 接口。它或多或少都算是声明式接口描述的标准。坦白说我真的不知道那些编写庞大却毫无描述的接口的人们是如何做到的。

一方面我们把 Swagger 作为声明式 REST 接口的标准,另一方面也可以这么看 GraphQL,我们可以看到它们其实非常相似,只是除此之外 Swagger 还尝试去描述 HTTP 细节和业务逻辑。它们都描述了传入参数和传出响应的类型。这意味着我们可以在它们之间写适配器!



REST 路径是这样子的

GET /user/id

可以采用 GraphQL 类型。

所以现在我们只需一个库来帮助我们自动转换。下面这个就是!

github.com/yarax/swagg…

Swagger2graphQL 接收你的 Swagger schema 然后返回 GraphQL schema,同时解析程序将自动构建 HTTP 请求到已有的 REST 路径上。

它被构建为一个将拥有超过 150 个路径的真实大型系统迁移到 GraphQL 的副项目。我们需要在做功和问题都最少的情况下尽快地迁移到 GraphQL。

只需要克隆资源库,运行

npm install && npm start

然后访问 http://localhost:3009/graphql

你会看到封装在 petstore.swagger.io/ Swagger 示例接口上的 GraphQL 接口。

而且,有了 Swagger 和 GraphQL 编写新的路径将变得十分方便。如果你早就熟悉 GraphQL,你可能会发现有时候类型描述看起来相当冗长,因为你需要去创建大量的隐式类型。Swagger2graphQL 可以自动完成这些步骤,你只需要在 Swagger schema 中创建一个新的带有声明的路径,通常这很简单。

如果你遇到任何困难或者有疑问请向我提 issue!

同时你也可以在 Twitter 上找到我





原文发布时间为:2017年8月12日


本文来自合作伙伴掘金,了解相关信息可以关注掘金网站。

时间: 2024-11-07 05:16:09

[译] 将现有的 API 从 REST 迁移到 GraphQL的相关文章

将 Java 小程序迁移到 Microsoft J# 浏览器控件

程序|控件|浏览器 Visual J# .NET 小组 Microsoft Corporation 摘要:通过 Microsoft J# 浏览器控件,开发人员可以将所编写的在 Java 虚拟机上运行的 Java 小程序迁移到 .NET 框架.本文向开发人员介绍 J# 浏览器控件,并说明将 Java 小程序迁移到 .NET 框架的步骤.本文还讨论了其他一些主题,如 J# 浏览器控件的安全性和调试,以及当前版本中不受支持的功能. 下载 HTML 小程序到对象标记转换器 (95KB) 本文假设开发人员

什么是API?如何做到API兼容?如何评估API?

文章描述:本文主要介绍什么是API,以及API兼容的重要性,最终给出方案如何评估API,以及如何做到API兼容. 本文主要介绍什么是API,以及API兼容的重要性,最终给出方案如何评估API,以及如何做到API兼容. What's API? API的全称是application programming interface. 而很多时候,程序开发者仅仅把函数.类的接口做为API的一部分,而忽略了其他重要的编程接口. 事实上,在前端Javscript编程中常见的API包括: 函数.类接口,包括参数,

如何设计一套事件日志API

简介 业界目前已经在以下这一点上达成了强烈的共识:API的设计应该是按照前端到后端的次序进行的,将重点放在开发者对API的使用上.在某个发展兴旺的商业体中,通常会存在着许多互相竞争的产品与API的实现,而易于使用.并且设计良好的API在吸引与保留开发者这一点更有优势.此外,新的工具不断涌现,它们不仅能够帮助开发者按照迭代方式设计API,而且能够帮助开发者学习与使用这些API. API设计中的关键因素在于"人",这意味着API设计工具与文档格式必须便于人的读写,这一段时期以来的API设计

将J2EE项目迁移到IBM Lotus Expeditor V6.1

简介:使用 IBM Lotus Expeditor Toolkit 将 J2EE 项目迁移到 IBM Lotus Expeditor V6.1,然后 把迁移后的项目部署在 Lotus Expeditor 运行时上.本文讲解迁移 J2EE 项目所需的步骤以及 Lotus Expeditor 不支持的 J2EE 特性. IBM Lotus Expeditor 这种 IBM 产品支持用熟悉的编程模型将 J2EE 应用程序迁移到客户机上.IBM Lotus Expeditor Toolkit 使开发人员

使用开放API和工具快速开发情景式mashup应用

Google 地图.屏幕抓取.微软必应.雅虎 Pipes.Delicious.Flickr.Identi.ca 情景式应用是快速开发的满足用户特定需求的"足够好"的应用.mashup 作为快速整合数据的一种应用开发模式,能够非常快速的把与某个主题相关的信息整合在一起,以满足情景式应用的需求.情景式 mashup 应用要求能够比较快速的构建,利用开放 API 和工具就成为最佳的选择. 在 Web 2.0 的时代,每个人的热情和创造性都被释放出来,张扬自己的个性.一方面,用户不再满足于大而

如何设计一个优秀的API(转载)

最近在整理框架的一些 API,觉得很有必要总结一下 API 兼容性的设计.下图是我自己当下的一些总结,慢慢维护: 网上搜索了一下,一个多月前,"标点符"已经发布了下面这篇文章,觉得写得非常不错,转载于此:   --------------------------------------------原文如下:-------------------------------------------- 到目前为止,已经负责API接近两年了,这两年中发现现有的API存在的问题越来越多,但很多AP

Flink Table/SQL API 规划 —— Dynamic Table

动态表的概念是社区很早就提出的但并没有全部实现下文中所有介绍都是基于已有规划和proposal给出的,可能与之后实现存在出入仅供参考 概念 动态表直观上看是一个类似于数据库中的Materialized View概念.动态表随着时间改变:类似静态的batch table一样可以用标准SQL进行查询然后一个新的动态表:可以和流无损地互相转换(对偶的).对现有的API最大的改进关键在表的内容随着时间改变,而现在的状态只是append.当前的streaming table可以认为是一种动态表,appen

Dropbox发布具有可伸缩性的API

在我们构建新的API时,人们通常会在未来的不可知和对棘手问题的预优化之间感到迷茫.Dropbox也不例外.构建API时,Dropbox开发人员必须考虑到作为一家公司可能会出现的快速增长,同时也需要认识到,他们对API做出的任何变更,随着时间的推移总会被一部分API消费者认为是在倒退.那么他们最终是怎么解决这些问题的?答案是三思而后行. Leah Culver之前曾是Dropbox的一名开发人员,他去年发表了一篇博文,文中详细阐述了Dropbox针对自身的API,从V1版本到V2版本的艰难升级过程

StopLight推出可视化的API设计工具

StopLight推出了一款新的可视化API设计工具和云服务,旨在将API的不同种类规格抽离成一个单一的接口. 该报道指出,其目标是为APIs提供一个协同接口,让更多的企业可以做贡献: 现有的工具(如Apiary和SwaggerHub)需要了解OAI.RAML或者JSON规范.StopLight以模型为中心的方法让更多使用API的人能够贡献并获得最大利益. StopLight创始人 Marc MacLeod 告诉 TheNewStack, "我希望当人们需要一种更 全面的解决方案时,它能够成为S