带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

点击查看第二章
点击查看第三章
GraphQL学习指南

带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

[美] Eve Porcello
Alex Banks 著
郭笑鹏 译
机械工业出版社

第1章

欢迎来到GraphQL的世界
在被英国女王册封为爵士前,蒂姆 "伯纳斯 "李(Tim Berners-Lee,英国计算机科学家,万维网之父)同你我一样也是一名程序员。他曾就职于CERN(European Organization for Nuclear Research,欧洲核子研究组织)位于瑞典的欧洲粒子物理实验室,与一大批才华横溢的研究人员共事。在工作生涯中,伯纳斯想要帮助同事们分享彼此的想法,因此他决定建立一个网络,通过它科学家们可以发布和更新最新的信息。这个项目最终发展成了第一个Web服务器和第一个Web客户端,并于1990年12月由CERN(https://www.w3.org/People/Berners-Lee/Longer.html )正式推出,这便是我们耳熟能详的“WorldWideWeb”(万维网)浏览器(后更名为“Nexus”)。
通过这个项目,伯纳斯使研究人员们能够通过自己的电脑查看并更新网页内容。 “WorldWideWeb”由HTML、URL、浏览器以及一个所见即所得(WYSIWYG,What You See Is What You Get )的界面组成,便于用户更新浏览内容。
现如今,互联网早已超出了通过浏览器获取信息这一传统概念。它既是笔记本电脑,也是智能手机、智能手表,还是公交卡中的射频识别(RFID,Radio Frequency Identification)芯片,甚至可以成为管家机器人在你离家时帮你签收快递。
现如今,客户终端的数量跟以往相比早已不可同日而语,但我们所做的事情却始终如一:加载数据,越快越好。程序员们不断地改善着自己应用的性能,而原因却再简单不过—因为用户需要。用户认为我们的应用应该在任何条件下都能正常运行,他们可不管是2G功能机还是光纤网。速度就是唯一的准绳。应用越快访问网站的用户就越多,应用越快用户体验就越好,应用越快我们就越赚钱。
精准而快速地从服务器端获取数据是互联网永恒的主题。尽管本书会去研究一些过去的事情,但此时此刻我们要谈论的是现代解决方案。我们谈谈未来,我们谈谈GraphQL。

GraphQL是什么

GraphQL(http://www.graphql.cn )是一种API查询语言,也是一种用于实现数据查询的运行时(runtime)。GraphQL服务与传输方式没有关系,但通常基于HTTP协议。
为了演示GraphQL查询和返回的数据,我们调用星球大战数据API(https://graphql.org/swapi-gaphql/ )。该API是GraphQL封装的表述性状态传递方式(Representational State Transfer,即RESTful)API。我们就用它来发送查询并接收数据。
图1-1是GraphQL的查询流程示例。左侧为我们想要查询的数据。我们请求的是莱娅公主(Leia Organa)的数据,并且指定限定条件(personID:5)。接下来指定我们想要的三个数据字段:name、birthYear和created。右侧为我们获得的响应结果:数据以JSON格式返回,并且只包含我们所需要的数据。

带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

接下来我们来调整一下查询字段,不必担心,查询是交互式的。我们改变之后立刻就能看到新的结果。如图1-2所示,我们添加字段了filmConnection,并指定了次级字段,从而获得了莱娅公主登场的所有电影的名字。
在执行查询时,根据嵌套的查询字段可以遍历相关对象。这样我们就可以查询两种不同的数据类型而只发出一个HTTP请求。不必在多个对象之间来回查找数据,因为我们不需要的数据根本不会返回。使用GraphQL,用户只需一次请求就能获取所需的所有数据。
每当我们向GraphQL服务器请求数据时,它会自动通过类型检测系统进行验证。每个GraphQL服务器都会在其GraphQL Schema中定义数据类型。可以将类型检测系统看作是API数据的架构,并自定义数据对象的内容。举例来说,之前我们返回的Person对象大体如下:
type Person {

id: ID!
name: String
birthYear: String
eyeColor: String
gender: String
hairColor: String
height: Int
mass: Float
skinColor: String
homeworld: Planet
species: Species
filmConnection: PersonFilmsConnection
starshipConnection: PersonStarshipConnection
vehicleConnection: PersonVehiclesConnection
created: String
edited: String

}

带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

Person类型包括了莱娅公主可查询的所有字段及其类型。第3章将深入研究GraphQL的类型检测系统和模板。
GraphQL通常被称为声明式数据获取语言。简而言之,开发人员可根据他们需要的数据来列出请求的数据字段,而无须关注如何获得数据。许多语言都有其对应的GraphQL服务端库,包括C#、Clojure、Elixir、Erlang、Go、Groovy、Java、JavaScript、.NET、PHP、Python、Scala和Ruby注1。
本书将重点介绍如何使用JavaScript来构建GraphQL服务。同时书中讨论的所有GraphQL技术也同样适用于其他语言。

GraphQL规范

GraphQL是客户端和服务器之间通信的规范。俗话说无规矩不成方圆,规范描述的是语言的功能和特性。有了规范才能为社区和论坛提供使用该语言的通用词汇和最佳实践,让广大程序员也为之受益。
业内最耳熟能详的规范要数ECMAScript规范了。每隔一段时间,来自浏览器公司、技术公司和广大社区的代表们便济济一堂,对ECMAScript规范进行修订。GraphQL亦是如此,同样有一群爱好者聚在一起制定GraphQL的实现标准,以飧后来者。
规范发布后,GraphQL的作者们还分享了在JavaScript环境下部署GraphQL服务器的实现方案--graphql.js(https://github.com/graphql/graphql-js )。该方案作为推广GraphQL的先导性库有其积极意义,但并不意味着强制规定使用哪种语言来实现服务。它仅仅是一个向导。在了解了查询语言和类型检测系统之后,可以使用任何喜欢的语言来构建服务器。
那么如果规范和实现方案出现了分歧该如何解决,规范里面又是如何解释的呢?实际上,规范描述的是编写查询字段时应该使用的语言和语法,规定了类型检测系统以及该系统的执行和验证引擎。除此之外,规范并不进行强制性规定。它没有规定使用何种语言、如何存储数据或支持哪些客户。诚然查询语言有其指导原则,但项目的实际设计则完全取决于你自己(如果你想探究整个过程,可以浏览文档:https://facebook.github.io/graphql/ )。

GraphQL的设计原则

尽管GraphQL不会干涉你构建API的过程,但其确实针对如何考虑服务提供了一些指导方针:
分层
GraphQL查询字段层次分明。字段嵌套在其他字段当中,查询字段的结构与其返回的数据结构相似。
以产品为中心
GraphQL由两大要素驱动,即客户端所需的数据,以及客户端支持的语言和运行时。
强类型
GraphQL服务器由GraphQL类型检测系统提供支持。每个数据点在模板当中都有其特定的类型,并且均会进行验证。
客户端指定查询
GraphQL服务器提供功能供客户端使用。
类型自查
GraphQL语言能够查询GraphQL服务器的类型检测系统。
现在我们已经对GraphQL规范有了初步了解,接下来详述创建它的原因。

GraphQL的起源

时间回到2012年,那时Facebook决定重新构建原生移动应用。起因是公司的iOS和Android应用尚停留在围绕移动网站视图进行简单包装的阶段。他们也有自己的RESTful服务器和SQL数据库,可惜性能不佳,应用时不时就崩一下展示存在感。正因如此,工程师们意识到他们需要改进将数据发送到客户端应用的方式。
由李 "拜伦(Lee Byron)、尼克 "施洛克(Nick Schrock)和丹 "查菲尔(Dan Schafer)组成的团队决定从客户端角度重新考虑他们的数据。以此为契机,他们着手构建一种查询语言,它可以描述其所需数据模型的功能和需求,为公司的客户端/服务端提供便利。
2015年7月,该团队发布了最初的GraphQL规范以及基于JavaScript的实现库graphql.js。2016年9月,在Facebook内部使用了许多年后,GraphQL脱离了“技术预览”阶段,这宣告GraphQL正式进入生产环境。如今,GraphQL在几乎所有的Facebook数据获取方面发挥着不可替代的作用,并被IBM、Intuit、Airbnb等公司广泛采用。

数据传输的历史

回顾数据传输的历史,将会帮助我们更深刻地理解GraphQL呈现出的一些新想法。我们考虑数据传输时,总是试图搞清楚计算机之间如何来回传递数据。普遍的想法是,我们向远程服务器发送请求然后服务器返回响应数据。

远程过程调用

远程过程调用(remote procedure call,RPC)发明于20世纪60年代。远程过程调用由客户端发起,向远程计算机发起请求以执行某些操作。接下来,远程计算机则向客户端发送响应。那个年代的计算机虽然与今天所使用的不可同日而语,但是信息传输过程却基本相同,即客户端请求,服务器响应。

简单对象访问协议

20世纪90年代末,微软提出了简单对象访问协议(Simple Object Access Protocol,SOAP)。SOAP使用XML将消息编码并通过HTTP传输,集成了类型检测系统,并引入了面向资源的数据调用概念。SOAP所提供的结果具有可预测性,可惜的是由于其实现过于复杂而导致失败的概率也很高。

表述性状态传递(REST)

今天各位最熟悉的API范例就是表述性状态传递(Representational State Transfer,REST)。REST是罗伊 "菲尔丁(Roy Fielding)于2000年在其博士论文中提出来的一种软件架构风格。REST描述了一种面向资源的架构,用户可以通过执行GET、POST、PUT和DELETE等操作来浏览Web资源。他把资源网络看成虚拟状态机,并且用户执行的动作(GET、POST、PUT、DELETE)都是机器内的状态变化。站在今天的视角可能会觉得这是理所当然的,但在那个年代,这无疑是个划时代的想法。
在RESTful架构中,路由代表了信息。举例来说,从以下这些路由请求信息将产生特定的响应:
/api/food/hot-dog/
api/sport/skiing/
api/city/Lisbon
REST使我们可以利用各种接口创建数据模型,明显优于之前的架构。它提供了在日益复杂的Web中处理数据的新方法,且没有强制规定数据响应格式。起初,REST是同XML一起使用的。AJAX最开始是Asynchronous JavaScript And XML的首字母缩写,因为Ajax请求的响应数据被格式化为XML(现在Ajax已经是一个独立的单词了)。这让前端开发者很困惑:在JavaScript中使用数据前还要解析XML响应。
没过多久,道格拉斯 "克罗克福德(Douglas Crockford)开发出了JSON(JavaScript Object Notation)并将其标准化。JSON和语言无关,它提供的是一种优雅的数据格式,许多不同的语言都可以解析和使用它。紧接着,克罗克福德撰写了著名的《JavaScript: The Good Parts》,充分展示了JSON的优点。
RESTful API的影响不言而喻。所有的API开发者都从中获益。以至于有一些爱好者去和别人争论什么是RESTful,哪些不是RESTful,这些人被称为“REST党”(RESTafarians)。好了,既然RESTful API如此成功,那么拜伦他们缘何还要另起炉灶呢?这就要从REST的缺点说起了。

REST的缺点

GraphQL最初发布的时候,一些人将其吹捧为REST的替代品。“REST已经凉了啊!”早期的GraphQL使用者一边四处宣扬,一边怂恿别人把他们的RESTful API全部停用。如果在博客或者论坛上说这种话倒没什么,但是如此简单粗暴地将GraphQL描述为REST杀手未免有失偏颇。更为真实的原因是,随着网络的发展,REST在某些条件下已经显示出其局限性。GraphQL想要做的就是改善这一切。

过量获取

假设我们正在构建一个应用,使用的数据来自星球大战接口的RESTful API。首先,我们需要加载一些与角色编号1号和卢克 "天行者(Luke Skywalker)相关的数据。注4使用GET请求访问https://swapi.co/api/people/1/ ,得到的JSON数据如下:

带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

返回的数据太多了,远远超过了我们的需求。实际上我们只需要姓名、身高和体重的信息:

带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

这个例子充分展示了何为获取过量—我们获得了大量不需要的数据。客户端仅需要三个字段,而我们却返回了一个拥有16个键的对象,这样一来完全用不到的信息也通过网络进行发送,无形之中造成了浪费。
在GraphQL中,该请求该如何显示呢?我们仍旧期望取回Luke Skywalker的名字、身高和体重,如图1-3所示。

带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

左侧是我们发出的GraphQL查询字段。我们只请求所需的字段。右侧是我们收到的一个JSON响应,这次只有我们所请求的数据,没有额外的13个字段,无形中节省了从基站到手机的流量。只返回我们需要的数据,不多不少,响应更快也是理所当然的。

获取不足

项目经理刚刚在我们的办公桌旁刷新了一下,他想给星球大战应用添加一项功能。除了姓名、身高和体重外,还加上了卢克 "天行者所有参演电影的片段列表。这样一来,在我们从上个接口请求数据后则不得不调用其他接口请求数据,这使我们“捉襟见肘”。
为了获取每部电影的名字,我们需要从电影数组中的每个路由获取数据:

带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

获取这些数据需要向之前的接口(https://swapi.co/api/people/1/ )发出一个请求,然后再向每一部电影发出5个请求。对于每一部电影,我们所请求到的都是一个大对象,可我们只需要其中一个值。

带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

如果我们想要列出这部电影中的角色,就不得不发出更多的请求。这样一来,我们恐怕得再调用16次接口,数据不停地在客户端和服务器端之间往复,并且每个HTTP请求都会占用客户端资源并取回大量的无用数据,其结果就是降低了用户体验。倘若用户的网速或设备较慢,那么可能什么内容都看不到。
GraphQL的解决方案是定义一个嵌套的查询结构,然后一次取回所有请求数据,如图1-4所示。

带你读《GraphQL学习指南》之一:欢迎来到GraphQL的世界

采用GraphQL,我们仅需一次请求便可获得所需的数据,同时返回数据的结构和我们的查询结构相符合。

管理REST接口

另一个和RESTful API相关的抱怨是缺乏灵活性。有时候客户端的需求发生了变化,导致我们不得不创建新的接口。
按照这个星球大战RESTful API来说,我们不得不向数个路由发出请求。大型应用通常使用自定义接口来尽可能减少HTTP请求。你可能会突然发现接口文档多了一个接口,类似于/api/character-with-movie-title。这种开发方式恐怕会拖慢开发速度,因为设置新的接口通常意味着前后端团队需要开会来沟通。
GraphQL将传统的架构集成于一个接口。该接口可以充当网关并协调多个数据源,而且只有一个接口让数据结构更为简便。
在讨论REST的缺点时,值得注意的是好多公司同时使用了GraphQL和REST。设置GraphQL接口从RESTful API获取数据是使用GraphQL的最有效方法。也许这正是在你的公司里逐步推广GraphQL的好办法。

现实世界中的GraphQL

许多公司都使用GraphQL为他们的应用、网站和API提供支持。GitHub是世界上最早采用GraphQL的著名公司之一。它的REST API经历了三次迭代,并在公共API第4版中使用了GraphQL。就像网站上所说的那样,GitHub发现“能够精确定义你想要的数据(且只有你想要的数据)比第3版的RESTful API要强大太多”。
其他公司,如《纽约时报》、IBM、Twitter和Yelp等也推崇GraphQL。他们的团队成员经常在会议上宣传GraphQL的优点。
目前至少有3个专门的GraphQL会议:在旧金山举办的GraphQL峰会(GraphQL Summit)、赫尔辛基举办的GraphQL芬兰峰会(GraphQL Finland)和在柏林举办的GraphQL欧洲峰会(GraphQL Europe)。这些社区通过本地聚会和线上会议共同推进GraphQL的发展。

GraphQL客户端库

正如之前我们曾多次说过的,GraphQL只是一个规范。它并不关心你所用的是React、Vue或原生JavaScript甚至是浏览器。GraphQL只是对一些特定的问题有一些指导意见,但除此之外,项目架构的一切都由你自己决定。因此一些超出规范的GraphQL客户端库也像雨后春笋一般被开发出来。让我们来看一看。
GraphQL客户端库的出现加速了开发团队的工作流程,提高了应用的效率和性能。它们能处理诸如网络请求、数据缓存以及将数据注入用户界面等任务。当下有许多GraphQL客户端库,其中的佼佼者当属Relay(https://facebook.github.io/relay/ )和Apollo(https://www.apollographql.com/ )。
Relay是Facebook开发的客户端库,搭配React和React Native一起使用。Relay旨在成为React组件和从GraphQL服务器获取数据之间的纽带,现已被Facebook、GitHub、Twitch等公司广泛使用。
Apollo是由Meteor开发组开发的,并由社区驱动的客户端库,旨在围绕GraphQL构建更全面的工具库。Apollo支持所有的主流前端开发平台,并且与框架无关。Apollo还开发了一些工具,可以协助构建GraphQL服务、改善后端性能以及对GraphQL API进行性能监控。Airbnb、CNBC、《纽约时报》和Ticketmaster等公司也在其产品中使用了Apollo客户端库。
GraphQL的生态系统很庞大并且还在不断演进中,不过好消息是它的规范相当稳定。在接下来的章节中,我们将讨论如何编写模板和创建GraphQL服务端。在此过程中,网址https://github.com/moonhighway/learning-graphql/ 中有一些资料可以为你提供帮助。在这里你可以按章节找到有用的链接、示例和所有的项目文件。
在我们深入研究如何使用GraphQL之前,先来谈谈图论和GraphQL中那些奇思妙想的由来。

上一篇:下拉菜单;手风琴;九宫格的Jquery的使用实例


下一篇:Oracle数据库的引导过程