在前几天的文章《StateOfJS: 2018年JavaScript生态圈趋势报告》中,我们看到2018年GraphQL在数据层的发展势头很猛,大部分用户都用过并说Okay,但是如上图的数据所示,目前在中国的用户量还是很少的,大部分人甚至都没听说过。今天小丝就给大家介绍一下什么是GraphQL。1、为什么会出现GraphQL?提到API设计,人们通常会想到SOAP、RESTful等设计方式。自2000年RESTful的理论提出以来,在业界引起了很大的反响,因为这种设计理念更便于用户使用,所以很快就被大家所接受。我们知道REST是一种从服务器公开数据的流行方式。当初提到REST这个概念的时候,客户端应用的数据需求比较简单,开发速度也没有达到今天的水平。因此REST非常适合很多应用。但是,随着业务越来越复杂,客户对系统扩展性的要求越来越高,API环境发生了巨大的变化。具体而言,以下三个方面对api设计方式提出了挑战:1.移动用户的爆发式增长需要更高效的数据加载。Facebook开发GraphQL的最初原因是移动用户、低功耗设备和松散网络的增加。GraphQL最大限度地减少了需要通过网络传输的数据量,极大地改善了在这些条件下运行的应用程序。2.各种前端框架和平台前端框架和平台运行客户端应用程序的异构环境使我们很难构建和维护满足所有需求的API。使用GraphQL,每个客户端都可以准确地访问它需要的数据。3.不同前端框架和平台下产品快速开发的难度越来越大。持续部署已经成为很多公司的标配,快速迭代和频繁的产品更新必不可少。使用RESTAPI,通常需要修改服务器公开数据的方式以满足客户端的特定需求和设计更改。这阻碍了快速开发实践和产品迭代。2.GraphQL官方定义:API查询语言GraphQL既是API查询语言,又是满足你数据查询的运行时。GraphQL为你的API中的数据提供了一套全面的易于理解的描述,使客户端能够准确地获得它需要的数据而没有任何冗余,使API更容易随时间演进,并且可以用来构建强大的开发者工具。询问您想要的数据:不多也不少。对您的API的单个GraphQL请求将为您提供您想要的数据,不多也不少。GraphQL查询总是返回可预测的结果。使用GraphQL的应用程序可以快速可靠地工作,因为应用程序控制数据,而不是服务器。获取多个资源:一次请求GraphQL查询不仅可以获取资源的属性,还可以沿着资源之间的引用进一步查询。典型的RESTAPI在请求多个资源时会加载多个URL,而GraphQL可以通过单个请求获取应用程序所需的所有数据。这样,即使在移动网络连接速度较慢的情况下,使用GraphQL的应用程序也可以足够快地执行。描述所有可能性:类型系统GraphQLAPI是根据类型和字段而不是入口端点组织的。您可以通过单个入口点获得所有数据功能。GraphQL使用类型来确保应用程序只请求可能的数据,并提供清晰且有用的错误消息。应用程序可以在不编写手动解析代码的情况下使用类型。3.GraphQL和RESTful的区别前面提到,GraphQL可以理解为基于RESTful的封装,目的是构建一个让客户端更容易使用的服务。可以说GraphQL是一种更好的RESTful设计。在过去十年左右的时间里,REST已经成为设计WebAPI的标准(尽管只是一个模糊的标准)。它提供了一些很棒的想法,例如无状态服务器和结构化资源访问。然而,事实证明RESTAPI过于僵化,无法跟上访问它们的客户快速变化的需求。GraphQL的开发是为了应对更多的灵活性和效率,它解决了开发人员在与RESTAPI交互时遇到的许多缺点和低效问题。为了说明从API获取数据时REST和GraphQL之间的主要区别,让我们考虑一个简单的示例场景:在博客应用程序中,应用程序需要显示特定用户文章的标题。同一屏幕还显示用户最近3位关注者的姓名。REST和GraphQL如何解决这种情况?在使用RESTAPI时,我们通常可以通过访问多个请求来收集数据。例如本例中,我们可以实现以下三个步骤:通过/user/获取初始用户数据通过/user//posts/user//followers返回用户的所有post请求返回每个用户的关注者列表的调用关系如下图所示:如果我们使用GraphQL,我们只需要一次请求就可以完成上述需求。在GraphQL的世界里,我们不需要获取更多的数据,也不必担心获取的数据变少。我们只需要按需获取它。REST最常见的问题之一是API返回过多或过少的数据。这是因为客户端下载数据的唯一方法是访问返回固定数据结构的端点。这使得我们设计一个API变得非常困难,因为它既能为客户提供准确的数据需求,又能满足不同调用者的需求,这本身就是矛盾的。GraphQL的发明者LeeByron提出了一个非常重要的概念:“Thinkwithgraphs,notendpoints”。通过上面的可视化展示,我们可以得出以下几点:1.获取了大量的冗余数据。通常,当我们调用通用API接口时,客户端会获得比应用程序实际需要的更多的信息。例如,UI需要显示用户列表,而实际上它只需要使用他们的名字。/user端点通常在RESTAPI中调用,并接收包含用户数据的JSON数组。但是此响应可能包含有关返回用户的更多信息,例如他们的生日或地址,这对客户端来说毫无用处,因为它只需要显示用户的名字。2.获取的数据少于客户需要的数据。一般来说,数据获取不足是指某个特定的端点没有为客户端提供足够的信息,客户端将需要额外的请求来获取它需要的一切。这可能会升级到客户端需要先获取列表信息,然后需要为单个数据添加额外请求以获取其他所需数据的程度。3、前端的快速产品迭代对API提出了很大的挑战。RESTAPI的一个常见模式是在应用程序内部根据你的表现逻辑构造端点,这很方便,因为它允许客户端访问相应的端点以获得特定视图所需的所有信息。这种方法的主要缺点是它不允许前端的快速迭代。对于对UI所做的每一次更改,现在都存在比以前拥有更多(或更少)数据的高风险。因此,需要调整后端以满足新的数据需求,这会降低生产率并显着降低将用户反馈集成到产品中的能力。使用GraphQL这个问题就解决了。由于GraphQL的灵活性,可以在客户端进行更改,而无需在服务器上进行额外的工作。由于客户端可以指定准确的数据需求,当前端的设计和数据需求发生变化时,不需要对后端API做任何改动来满足表现层的变化。4.Schema和类型系统的好处GraphQL使用强大的类型系统来定义API功能。API中公开的所有类型都使用GraphQL模式定义语言(SDL)以模式编写。模式充当客户端和服务器之间的合同,用于定义客户端访问数据的方式。一旦模式被定义,前端和后端团队可以在没有进一步沟通的情况下完成他们的工作,因为他们都知道通过线路发送的数据的确切结构。前端团队可以通过模拟所需的数据结构轻松地测试他们的应用程序。一旦实现了后端API,就可以切换到客户端应用调用实际的API来获取数据,这也让我们能够更好的实现客户端和服务端的分离。4.GraphQLGrammarBasicGrammar其实GraphQL需要学习的语法很少。大部分语法和我们平时的语法是一致的。您可以通过官方网站了解更多信息。首先,GraphQL是一种强类型语言,所以就像我们在数据库中定义一个表一样,我们需要定义每个属性的类型。如下图所示:下面是一个简单的类型定义,首先定义了一个枚举,然后我们定义了一个类型,有四个属性:id、name、friends、appearsIn,其中id和name是标量类型,friends是一个Person类型,这是一个嵌套类型。仔细想想应该没什么问题,毕竟你的朋友和你一样也是人,appearsIn是枚举类型,看起来还是很眼熟的。enumEpisode{NEWHOPEEMPIREJEDI}typePerson{id:ID!名称:字符串!朋友:[Person]出现在:[Episode]!}了解完类型,我们再来看看Arguments和resolver,这两个都是比较服务端的。但是看一看,对graphql的使用原理有了更深的理解。对于一个RestfulAPI,除了知道接口的URL,我们还需要知道接口传参的定义。GraphQL也是如此。虽然只有一个URL,以类型区分不同的接口,但是参数传递和RestfulAPI是一样的。客户端和服务器之间的交互。比如如下,查询的目标是id=2的用户,获取他的用户名:Query{user(id:2){iduserName}}在服务端定义接口的时候,我们也需要定义入参,主要从两个方面来说,一个是类型,一个是是否需要,比如下面这样:interfacedefinitionuser:{type:UserType,args:{id:{type:GraphQLID}},解析:(root,args,context,info)=>{const{id}=args;返回getUser(id);}}查询定义上面的代码只定义了一个输入属性id,并没有定义是否必填,所以在查询的时候,如果没有配置Queryid,查询不会报错,只会得到一个空值结果。但讲道理,我们希望这是必填项,所以我们需要修改服务端的代码,将id:{type:GraphQLID}替换为id:{type:newGraphQLNonNull(GraphQLID)}。这段代码的意思是表示id是一个ID类型的必填项。再次执行我们的查询得到如下错误信息,说明id是必填的ID类型,同时右侧也没有得到空的查询结果。在上面说到Arguments的时候,可以零星看到type中有一个resolve方法,它接收四个参数:root、args、context、info。其中,root表示父节点在该类型上的解析值(因为GraphQL支持嵌套查询),args是上面提到的上下文表中Resolver解析链传递的中间变量,类似于react的上下文,以及info的概念,就是当前Query的AST对象,比较抽象,但是可以通过查看info得到这个Query的编译对象。该方法也是后端服务编写的重要组成部分,我们在这里常常可以将其与现有的RestfulAPI联系起来。核心概念Schema可以说是GraphQL的核心部分,它描述了整个接口对外暴露的形式。和RestfulAPI一样,我们定义一个查询所有人的接口url:/api/v1/user/getUsers查询一个人的具体信息的接口url为:/api/v1/user/getUserById为人员新增一个接口url定义就是:/api/v1/user/createUser这样前端人员调用起来会很直观。但是graphql的使用方式完全不同。暴露给前端的url就像/api/graphql,那么这么多接口怎么区分呢?我们来看看:奥秘就是上图,一个graphql接口有一个Schema定义。它定义了三种操作模式:查询(query)、变异(change)和订阅(monitor)。再往下,一个query包含多个字段,也就是各种不同的query,比如queryuser查询person,querymessage查询message,queryweather查询weather。通过这些,RestfulAPI使用多个url来实现不同操作的效果。总结:今天我们只是讲了GraphQL的一些基础知识,但是还是可以看到,GraphQL的出现可以让我们的后端API更加灵活和可扩展,满足不同客户端对数据的需求,大大丰富了GraphQL提供的能力API数据。部分内容来源:https://segmentfault.com/a/11...