GraphQL 如何一次获取多个资源?

广告

Vue.js小书已经出版,尤小右作序推荐:http://www.ituring.com.cn/boo...
欢迎购买。
Swift iOS 小书 http://www.ituring.com.cn/boo...

正文

GraphQL 原来2012年就已经开源,算来也有不少历史了,但是看起来网络资料并不太多,大家普遍还是觉得麻烦。单单看官方手册好像就太不亲人的,太容易从自己的角度去描述细节,而不是从使用的角度去剖析,这也是官方手册普遍的问题。

比如“获取多个资源,只用一个请求”,官方说:

GraphQL 查询不仅能够获得资源的属性,还能沿着资源间引用进一步查询。典型的 REST API 请求多个资源时得载入多个 URL,而 GraphQL 可以通过一次请求就获取你应用所需的所有数据。这样一来,即使是比较慢的移动网络连接下,使用 GraphQL 的应用也能表现得足够迅速。

因为他假设你知道REST API,并且和它对比。其实,认识一个新事物,认识它本身会更直接,认识清楚了,想要对比了再去对比才有价值。但是人们太喜欢使用类别了。

我曾经写过一个高点击率的文章,讲述了vuex是什么,因为大家普遍反映官方文档不好懂,原因是是它上来和reactive那套东西对比。作者这样做可以理解,因为他就是对比着做的,说出来的也是对比的话,也认为这是干货。但是读者就不太好了解,因为我vue还没有搞利索,现在你让我搞搞reactive才能动vue的东西。这很令人绝望。

我们还是从一个案例开始。假设我有两个数据实体,一个是book,一个是author,且book和author是1:对多的关系。它的数据样本,看起来是这样的:

var books = [
    {id:0,title:"null book",author:{name:"reco"}},
    {id:1,title:"the little prince",author:{name:"reco"}},
    {id:2,title:"the http book",author:{name:"reco"}}]
var authors = [
    {id:1,name:"reco",books:[{title:"the little prince"},{title:"the http book"}]},    
    {id:2,name:"rita",books:[{title:"the swift book"}]}]

就是这样的数据源。如果使用Graphql来做查询,可以查询作者列表,且对作者对书籍的引用做进一步查询,也就是希望这样的查询:


{authors{name,books{title}}}

可以返回:

{
  "data": {
    "authors": [
      {
        "name": "reco",
        "books": [
          {
            "title": "the little prince"
          },
          {
            "title": "the http book"
          }
        ]
      },
      {
        "name": "rita",
        "books": [
          {
            "title": "the swift book"
          }
        ]
      }
    ]
  }
}

对author.name的查询,就是获取对象属性,是比较容易的,而对而对关联对象的延伸查询,其实和属性一模一样,只不过看起来是嵌套的而已。
明确了目标,我们把代码跑起来,也还是typeDefs+resolvers的一套东西:

const typeDefs = `type Book {
  title: String
  author: Author
}
type Author {
  name: String
  books: [Book]
}
type Query {
  books:[Book]
  single(id:String):Book
  authors:[Author]
}`
resolvers = {
    Query:{
        // {books{title}}
        async books(root,{},context) {            
            return books
        },
        // {authors{name,books{title}}}
        async authors(root,{},context) {            
            return authors
        },
        // {single(id:"2"){title,author{name}}}
        async  single(root,{id},context){
          for (var i = 1; i < books.length; i++) {
              var item = books[i]
              if (item.id == id)return item;
          }
          return books[0]
        }, 
    },    
}

你可以把它先跑起来,完整代码在这里。你可以在localhost:4000/graphql内输入{authors{name,books{title}}},了解查询的结果。然后再看代码,它简单到不必解释。

如果换成RESTAPI,那么你需要定义的是这样的资源,book和author在REST内就被称为资源:

GET /book
GET /author

且仅仅看这个资源,作为开发者,是无法知道book会返回哪些属性的,当然也无法从定义上看到author后面有book还是没有,你必须有手册去告诉开发者。如果没有,是否应该自己去查询book资源,如果有,那么和book资源查询重复,所以,实践上来说,常常是分别定义,自己查自己的。为了效率才会不在乎重复。官方说:“典型的 REST API 请求多个资源时得载入多个 URL”。

另外,除非你自己解析参数,前端开发者也无法很好的告诉后端在某个场景下,他需要那些属性,那些属性他并不需要。在这里案例里面,我们可以举例说,在某个界面我只需要author.name属性,另外一个界面,我还额外需要author.book.title。当然这些在graphql都可以做到。

使用graphql,前端可以指定查author.name

{authors{name}}

或者只查author.book.title

{authors{books{title}}}

后者就是通过author在关联了book,也就是"还能沿着资源间引用进一步查询"。

回头看官方网页的这句话:比如“获取多个资源,只用一个请求”,官方说:

GraphQL 查询不仅能够获得资源的属性,还能沿着资源间引用进一步查询。典型的 REST API 请求多个资源时得载入多个 URL,而 GraphQL 可以通过一次请求就获取你应用所需的所有数据。这样一来,即使是比较慢的移动网络连接下,使用 GraphQL 的应用也能表现得足够迅速。

对比REST,再对照可运行的代码,我想应该容易理解多了。

广告

Vue.js小书已经出版,尤小右作序推荐:http://www.ituring.com.cn/boo...
欢迎购买。
Swift iOS 小书 http://www.ituring.com.cn/boo...

你可能感兴趣的:(graphql)