开源中国

我们不支持 IE 10 及以下版本浏览器

It appears you’re using an unsupported browser

为了获得更好的浏览体验,我们强烈建议您使用较新版本的 Chrome、 Firefox、 Safari 等,或者升级到最新版本的IE浏览器。 如果您使用的是 IE 11 或以上版本,请关闭“兼容性视图”。
GraphQL,高效、结构化与系统化的 REST 替代方案 - 技术翻译 - 开源中国社区

GraphQL,高效、结构化与系统化的 REST 替代方案 【已翻译100%】

标签: <无>
oschina 推荐于 1个月前 (共 8 段, 翻译完成于 05-24) 评论 10
收藏  
31
推荐标签: 待读

在提及web API的时候,我们大多都会想到REST(表述性状态传递,Representational State Transfer)。你发送请求到一个特定请求的URL,然后你会收到结果,就像是HTML,XML,JSON,明文,PDF,JPEG…这些应用可以理解的任何格式。

Facebook的web API系统,GraphQL,提供了一种新的定义API的方式。开发人员使用强类型查询语言来定义请求和响应,这可以让一个应用精确地指定它需要从API中获取哪些数据。因此GraphQL的目的是提供一个更高效,更结构化,更系统的方式来替代REST。

本文我们会展示GraphQL与REST的不同之处,这些不同是如何影响API设计的,以及在从服务器获取数据方面GraphQL为什么是比REST更好的选择。

琪花亿草
 翻译得不错哦!

GraphQL 对比 REST

使用REST,您一般会通过一个特制的URL来提交您的请求,并将每种请求发送到不同的终点——例如:/movie/2120 或者 /director/5130。

使用GraphQL,您可以在一个类似JSON的查询中为您正在搜索的数据提交一个陈述性请求,并且所有的请求都会发往同一个终点。用于请求的schema决定了您将得到的数据返回。这是一个标准化的、自我描述的方法来请求所需的具体数据,并且只是所需的数据。

不同的请求类型使用不同的schema,替代了使用不同终点的URL格式,使得查询机制更加灵活。虽然像Swagger这样的很多REST API也符合通用规范,没有规则说REST APT必须通过Swagger生成。GraphQL默认为API提供了一个形式定义。

从某种意义上来说,GraphQL有点像SQL(结构化查询语言)。使用SQL提供的数据源,您可以将所有数据请求连接到一个公共终点,并且请求的格式决定了您将得到什么样的记录返回。虽然SQL有许多不同的实现,但是SQL查询语法在这些实现之间保持高度一致。

kevinlinkai
 翻译得不错哦!

GraphQL 查询

GraphQL使用一个schema或者一个数据定义来描述在查询和响应中如何组织要检索的数据。任何使用ORM(对象关系映射器)的人都应该熟悉GraphQL的数据schema定义。


type Movie {
    id: ID
    title: String
    released: Date
    director: Director
}

type Director {
    id: ID
    name: String
    movies: [Movie]
}

您会注意到在schema中的每个元素都有一个类型定义。GraphQL有自己的查询类型系统,用于验证传入的schema并返回与定义格式一致的数据。

提交给GraphQL的查询类似通过一个schema定义:


type Query {
    movie(id: ID!): Movie
    director(id: ID): Director
}

我们这有一个查询需要最多两个参数,movie(通过它的ID号)和director(也通过ID)。

类型旁边的“!”表示这是查询中一个强制元素。换句话说,您必须通过ID查询movie,director是可选项。强制元素也可以使用在数据schema中。

这是使用上面的schema来定义的查询格式的一种可行方法:


query GetMovieByID ($id: ID!) {
    movie(id: $id) {
        name
    }
}

这个查询使用了一个必需的单独定义变量($id),通过ID号码查找movie并返回它的name。需要注意的是,GraphQL查询可以通过字段内嵌套的数组来返回相关对象和字段,而不是只能返回单个字段。

像这样的查询变量在查询的一个单独的部分传递,使用如下格式:


{
    “id”: 23
}



kevinlinkai
 翻译得不错哦!

GraphQL 类型

GraphQL的查询类型系统说明了许多常见的标量类型,像strings和integers。大多数查询将通过他们重写。但是这些类型系统也包括了几种用于更复杂查询工作的高级类型。

  • interface类型能用来创建一个预定义字段集合的抽象类型,其他的类型可以实现和复用。

  • union类型允许从单一类型的查询中穿过多种类型返回不同类型的结果。

  • input类型能用来传递上述类型的整个对象作为查询参数,前提是这些对象是用可验证的常用标量类型创建的。

如果您使用interface或者union,您将需要使用内联片段指令来返回数据,这些数据基于这些对象类型可指定的条件。

可以在查询中返回的另一种类型是边缘类型,在可选边缘字段返回。边缘包含节点——实质上是记录——和游标,他们是编码字符串,提供关于如何从该对象向前或者向后翻页的上下文信息。

{
    movie {
        name
        actors (first:5) {
            edges {
                cursor
                node {
                    name
                }
            }
        }
    }
}

这个例子中,一个movie节点将返回movie的name和actors的name。对于movie中的每个actor,我们都会收到一个节点,这个节点包含actor的name和允许浏览actor的“邻居”的光标。

kevinlinkai
 翻译得不错哦!

GraphQL 分布

处理任何数据源时的常见情况是通过光标请求页面中的数据。GraphQL提供了多种分页的方式。

当你请求记录时,你不仅可以指定要请求的记录数和起始偏移量,还可以指定如何请求连续页面。上一节中的示例代码仅返回与给定影片相关联的前五位演员 - 和括号中的first:5参数所表示的一样。

actors之后的first:子句可以紧跟其他描述如何获取后续项的关键字。offset:可用于简单偏移量,但添加或删除数据时偏移量可能会被丢弃。

要获得最健壮的分页,你需要使用可以与请求的对象一起传递的光标,通过使用上述的edge类型。这允许你创建在分页之间插入或删除数据时不会被打断的分页机制 - 例如,通过将对象的唯一ID用作其他计算的起始键索引。

Tocy
 翻译得不错哦!

GraphQL的mutations

使用REST API,您可以通过使用POST、PATCH和其他HTTP动作提交请求来改变服务器端的数据。使用GraphGL,您可以使用特定的查询schema做出改变,一个mutation查询——再一次,与SQL使用UPDATE或DELETE同样的方式查询。

为了改变数据,需要您使用一个叫做mutation的schema来提交GraphQL查询。

mutation CreateMovie ($title: String!, $released: Date!) {
    createMovie (title: $title, released: $released){
        id
        title
        released
    }
}

[submitted data]

{
    “title”: “Seven Samurai”
    “released”: “1950”
}

包括mutation查询在内的所有的查询都能返回数据。在例子中,createMovie后面的大括号中的字段列表指定了在使用该请求创建新纪录之后,从服务器返回的内容。这种情况下,id字段的值将由数据库创建;其他字段的值将在查询中提交。

需要记住的另外一件事情,用于返回数据的查询和数据类型在设计上不同于用于请求数据的查询和数据类型。Mutation查询需要校验传入的数据,所以这些查询使用的类型意味着服务该功能。同样,返回查询对象中使用的字段用于显示而不是验证。如果您从查询中得到了一个GraphQL对象返回,那它可能带有循环引用或者其他问题的字段,使得它不能用于查询参数。

kevinlinkai
 翻译得不错哦!

为什么使用GraphQL

GraphQL查询具有明确声明特性是选择GraphQL而不选择REST的一个关键原因。查询和返回数据有个正式定义看起来应该是有好处的,不只是为了与API和实现方面保持一致。

正如Phil Sturgeon在他关于GraphQL与REST的考察报告中所指出的那样,GraphQL字段结构能更容易的使用更细化的版本来查询。因为会被弃用或者随着时间流逝是特定字段,而不是整个API版本。GraphQL还可以使用批量版本管理方法; 关键是在推出变更时您不会被迫这么做。

Apollo GraphQL的工程经理Sashko Stubailo说,GraphQL API的开源工具制造商指出了GraphQL方法的另一个优点:自文档化。Stubailo写到:“每个可能的查询、对象和字段都具有名称、描述和类型信息,可以用标准方法从服务器查询。”

GraphQL的自文档性质提供了一种“自我反省”,它意味着您可以使用查询返回与它自己相关的信息。用这个方法,使用GraphQL查询来工作的软件可以不用强制处理特定的字段集合;它能自动推断出这些字段。

也就是说,GraphQL比较新,REST/Swagger比较老的这个事实不应该成为支持前者的原因。正如《每日API设计》的作者Arnaud Lauret在讨论两个标准时所说的:“一个GraphQL API就像一个REST API一样,必须是为了达成某个目的而创建,并且从是由外而内的设计而不是由内而外的。”

kevinlinkai
 翻译得不错哦!

Serdar Yegulalp:Serdar Yegulalp是InfoWorld的资深作家,专注于机器学习、容器化、devops、Python生态系统和定期评审。

Tocy
 翻译得不错哦!
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们
评论(10)
Ctrl/CMD+Enter

说这么多,还不如直接让客户端连Mongodb
还不如 OData 了。
就是把用SQL能1分钟写好的表达式转成了要开发10分钟的技术.
GraphQL也屬於REST呀。這文真水。

引用来自“啦啦啦拉拉”的评论

说这么多,还不如直接让客户端连Mongodb
出于安全考虑,有些业务逻辑不能放客户端。
说的这么多,没卵用。
目前 Schema 声明语言还是很挫逼. 其它还好

引用来自“啦啦啦拉拉”的评论

说这么多,还不如直接让客户端连Mongodb

引用来自“QiHaiYan”的评论

出于安全考虑,有些业务逻辑不能放客户端。
GraphQL写业务逻辑太头疼
1、怎么将后端的model暴露给前端?
2、解析GraphQL协议的代码由谁负责?后端开发人员?框架?分布式的数据库?
3、权限模块,怎么跟GraphQL协议一起工作?
完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能
https://juejin.im/post/5b13cda1f265da6e4a6bcfee
顶部