前端应该知道的GraphQL

1,608 阅读4分钟

本文主要结合GitHub GraphQL API,从前端使用者的角度来谈GraphQL,没有GraphQL项目的同学可以拿GitHub GraphQL API练手,具体代码可参见我的GitHub Blog,欢迎star、fork。

为什么需要GraphQL?

以我的博客为例,目前列表页,每篇文章需要的数据结构如下:

{
    "title": "前端应该知道的GraphQL",
    "updatedAt": "2018-04-22T03:46:34Z",
    "bodyText": "本文主要结合...",
}

而文章详情页的数据结构为:

{
    "title": "前端应该知道的GraphQL",
    "updatedAt": "2018-04-22T03:46:34Z",
    "bodyHTML": "<p>本文主要结合...",
}

又想记录下文章的浏览量,日后成为大V,再展示出来 hhh~

{
    "title": "前端应该知道的GraphQL",
    "updatedAt": "2018-04-22T03:46:34Z",
    "bodyHTML": "<p>本文主要结合...",
    "view": "29898",
}

那么问题来了:两个页面的数据结构title和updateAt的数据是重复的,而body是不同的,并且还有一个希望现在就设计好以后需要的时候再用到的view字段。如果为了方便,只写一个接口,同时返回bodyText和bodyHTML,那总有数据是多余的,这样也不合理。但如果分两个接口,又显的有点麻烦和浪费。

这还只是一个简单的例子,平时开发过程中,需求变化特别频繁,遇到的问题也会更复杂,目前主流的RESTful API所暴露出来的问题也越来越明显。

如果能从源头出发,接口返回的数据不是由生产方(后端),而是由使用方(前端)来决定,就可以达到所见即所得的效果,这时候GraphQL也就应运而生了。

什么是GraphQL?

先贴官网:英文 | 中文

GraphQL 既是一种用于 API 的查询语言,也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。

也就是说,GraphQL能够在你调用api的时候来决定api返回的数据结构,以此达到精准、没有冗余的拿到所需要的数据。GraphQL这么厉害,是如何做到的呢?我们先从我的博客文章详情页接口入手来揭示GraphQL的庐山真面目:

let data = {
  query: `query {
      repository(owner:"simbawus", name: "blog") {
        issue(number: ${articleId}) {
          title
          updatedAt
          bodyHTML
        }
      }
    }`
};

Actions.getIssues(data).then((res) => {
  let issue = res.data.data.repository.issue;

  this.setState({
      title: issue.title,
      updatedAt: new Date(issue.updatedAt).format('yyyy-MM-dd'),
      bodyHTML: issue.bodyHTML
  })
})

这就是一个基于GitHub GraphQL API的请求,跟普通请求唯一的区别就在请求参数data,并不是 JSON 对象,而是一个字符串,这个字符串描述了客户端希望服务端返回数据的具体结构,如下JSON:

{
    "data": {
        "repository": {
            "issue": {
                "bodyHTML": "<p>本文主要结合...",
                "title": "前端应该知道的GraphQL",
                "updatedAt": "2018-04-22T03:46:34Z",
            }
        }
    }
}

结合这个例子,我来介绍GraphQL的几个核心概念:

query & mutation

query的中文意思是查询,也就对应RESTful标准中的get,而mutation的意思是变更,对应post、delete、patch和put。

connection

connection让你能在同一个请求中查询关联的对象。通过connection,你只需要一个GraphQL请求就可以完成RESTful API中多个请求才能做的事。

比如,GitHub GraphQL API文档中,我们在查询issue对象的同时,还可以查labels对象。

let data = {
  query: `query {
      repository(owner:"simbawus", name: "blog") {
        issue(number: ${articleId}) {
          title
          updatedAt
          bodyHTML
        }
        labels(first: 100){
          nodes{
            name
          }
        }
      }
    }`
};

field

field是你可以从对象中获取的数据单元。正如GraphQL官方文档所说:“GraphQL查询语言本质上就是从对象中选择field”。所有的GraphQL操作必须指明到最底层的field,并且返回值为标量,以确保响应结果的结构明白无误。

argument

argument跟RESTful API标准中一致,表示我们在请求该接口是传的参数,比如上面issue的number 参数,表示请求的第${articleId}个issue。

对于前端来说,在查询GraphQL API的时候基本都要了解上面说的这几个概念,具体应用可参见我的这篇文章如何利用GitHub GraphQL API开发个人博客?。详情代码可查看我的github:simbawus/blog,欢迎star、fork。

GraphQL的未来

GraphQL的优势想必大家都了解了,但为何这么好的技术并没有得到广泛的应用和推广呢?

  1. 要在前端爽爽地使用 GraphQL,必须得在服务端搭建符合 GraphQL spec 的接口,基本上是整个改写服务端暴露数据的方式。痛点是前端的,却要后端来改造,谁会去做?
  2. 改成GraphQL对用户体验来说并没有什么提升,而且对后端水平要求也高,改起来不简单,需要花费大量的时间,老板不用付你工资的吗?
  3. GraphQL意味着一个中心化的API网关,中心化流量要求巨大的中心化集群,技术上运维上又是一个难题。

基于以上,GraphQL目前基本也就一些比较有技术追求和实力的创业公司和一线大厂在使用,希望Facebook能更进一步,给出一个基于云端的解决方案,解放前端。

欢迎讨论,点个赞再走吧~

文章同步于以下社区,可以选一个关注我噢 。◕‿◕。

simbawu | github | segmentfault | 知乎 | 简书 | 掘金