GraphQL What?and Why?
REST是一种古老的面向服务端和客户端(CS)的架构风格。(2000年首次提出)
它定义了一系列严格的构建API的原则,用简单的方式描述资源,并认为大部分时候违背这些原则会让软件的扩展性受限。
随着服务端SOA和客户端Ajax的崛起,通信扩展问题变得越来越重要,REST得以广泛被运用。
在MicroService逐渐流行的今天,RESTful API已经成为主流。
如今,随着前端和移动端的迅猛发展,REST也面临严峻挑战。
RPC(一种远程调用)
存在问题:
1.资源分类导致性能受限
前端的效率主要来源于http请求
2.在现代场景中难于维护
然REST的目标是易于维护和扩展,但在Web前端/客户端领域,它的表现并没有想象得那么好。我们经常说最明显的Code smell就是重复。
3.缺乏约束
对REST来说,不同版本之间的兼容能力非常弱小。
4.严格,抽象,但并不能解决客户端问题
我们经常可以在网上看到互相指责的文章和讨论,基本上都是一方列举出自己使用RESTful API遇到的实际问题,而另一方认为前者实际应用违反了哪条REST原则,因此不是RESTful API。
GraphQL是什么?
GraphQL是一个查询语言,由Facebook开发,用于替换RESTful API。服务端可以用任何的语言实现。(2012年创建,2015年形成规范)
GraphQL优势:
1.需求驱动
减少了沟通成本
2.一次请求复杂数据
3.静态类型
4.兼容多版本
5.Mutation
GraphQL潜在的问题?
1.服务端优化
2.安全问题
3.需要重新思考Cache策略
那么 GraphQL 与 RESTful 的具体区别有什么呢?我觉得主要是两点。
1 入口 (entry point)
RESTful 的核心理念在于资源 (resource),且讲究一个 RESTful 接口仅操作单一资源;因此在你使用 RESTful 时,会设计出大量的接口。
GraphQL 是单一入口,一般配置在 [host]/graphql/,所有的资源都从该入口通过 graphql 的语句获取或修改(当然 GraphQL 亦支持多入口,但显然多入口的数量也远小于 RESTful)。
2 所见即所得
查询的返回结果就是输入的查询结构的精确映射
查询:
{ user(uid:1) { uid name } }
返回:
{ "data": { "user": { "uid": "1", "name": "xxx" } } }
3 减少网络请求次数
如果设计的数据结构是从属的(例如,上文中文章的作者信息),直接就能在查询语句中指定
{
article(aid:1) {
title
content
author {
uid
name
}
}
}
即使数据结构是独立的,也可以在查询语句中指定上下文,只需要一次网络请求,就能获得资源和子资源的数据(例如,上文中文章的评论信息)
{
article(aid:1) {
title
content
author {
uid
name
}
},
comment {
content,
author {
uid
name
}
}
}
4 代码即文档
GraphQL会把schema定义和相关的注释生成可视化的文档,从而使得代码的变更,直接就反映到最新的文档上,避免RESTful中手工维护可能会造成代码、文档不一致的问题。
5 参数类型强校验
RESTful方案本身没有对参数的类型做规定,往往都需要自行实现参数的校验机制,以确保安全。
但GraphQL提供了强类型的schema机制,从而天然确保了参数类型的合法性。
It’s Graphs All the Way Down *
它就像是一颗无限向下延伸的树。所以在我看来,GraphQL 更应该叫 TreeQL,当然在图论里,Tree 就是 Graph 也没毛病啦。需要注意的是,这也会引出 “N + 1 problem” 的话题——naive 的 GraphQL 服务端实现会让这段 query 变得异常慢!
怎么解决这个棘手的问题?
1.针对一对一的关系(比如我上面举例中提到的这个 User 与 UserScore 的关系),在从数据库里抓取数据时,就将所需数据 join 到一张表里。别等着 ORM 框架替你懒加载那些你需要的数据。
2.针对多对一或者多对多的关系,你就要用到一个叫做 DataLoader 的工具库了。其中,Facebook 为 Node.js 社区提供了 DataLoader 的实现。DataLoader 的主要功能是 batching & caching,可以将多次数据库查询的请求合并为一个,同时已经加载过的数据可以直接从 DataLoader 的缓存空间中获取到。