GraphQL
一、GraphQL简介
1、什么是GraphQL?
GraphQL官网:https://graphql.org/,这个是英文的,https://graphql.js.cool/这个是中文的。
GraphQL是一种用于API的查询语言。GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。 GraphQL 对你的 API 中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。
GraphQL与数据库、存储技术和开发语言、框架无关。GraphQL的服务也不限定使用的传输技术,但是通长是使用HTTP(S)来传输。
嵌套查询,查询是可以嵌套的,一次请求,获得多个类型的数据,无需继续钻取数据,客户端不会收到不需要的数据属性。
每当对GraphQL服务器进行查询的时候,都会使用类型系统进行验证。
在Schema里定义类型:
GraphQL通长被称作是“声明式数据获取语言”。
GraphQL的设计原则:
层次结构性、以产品为中心、强类型、客户端定制查询、内省(Introspective)
2、GraphQL的历史
源自Facebook,2012年Facebook开始开发,2015年开源
3、GraphQL和REST
至于REST的一些概念,开源参考一下之前的一篇随笔,点击这里
前面提到GraphQL可以理解为基于RESTful的一种封装,目的在于构建使Client更加易用的服务,可以说GraphQL是更好的RESTful设计。在过去的十多年中,REST已经成为设计web api的标准(虽然只是一个模糊的标准)。它提供了一些很棒的想法,比如无状态服务器和结构化的资源访问。然而REST api表现得过于僵化,无法跟上访问它们的客户的快速变化的需求。 GraphQL的开发是为了应付更多的灵活性和效率,它解决了与REST api交互时开发人员所经历的许多缺点和低效之处。 为了说明在从API获取数据时REST和GraphQL之间的主要区别,让我们考虑一个简单的示例场景:在blog应用程序中,应用程序需要显示特定用户的文章的标题。同一屏幕还显示该用户最后3个关注者的名称。REST和GraphQL如何解决这种情况?
使用REST API来现实时,我们通常可以通过访问多次请求来收集数据。比如在这个示例中,我们可以通过下面的三步来实现:
1、 通过 /user/<id>获取初始用户数据
2、 通过/user/<id>/posts 返回用户的所有帖子
3、 请求/user/<id>/followers,返回每个用户的关注者列表
调用关系如下图所示:
如果用GraphQL的话,我们只需要一次请求就可以完成上述的需求:
在GraphQL的世界里我们不用多取数据,也不用担心数据取少了,我们只需要按需获取即可。
REST最常见的问题之一是API的返回数据过多或者过少,这是因为客户端下载数据的唯一方法是通过访问返回固定数据结构的endpoint,这就会导致我们设计API非常困难,因为它既要能够为客户提供精确的数据需求,又需要满足不同调用者的需求,这本身就是相互矛盾的。GraphQL的发明者Lee Byron提出了一个很重要的概念: “用图形来思考,而不是endpoint”。
可以使用GraphQL管理REST端点
GitHub的API有四个版本,第三个版本使用REST,第四个就是用的GraphQL。https://developer.github.com/v4/explorer/
二、图论(GraphQL Theory)
图论就是研究图的,图开源用来表示一组关联的对象。可以把图看作是一个包含数据点和连接的对象。例如:人机关系图、家谱、公交线路图
这是一个无序图,一个图包含:
1、顶点Vertices
2、边Edge
3、G=(V,E)
G:图
V:顶点
E:边
上图中:
Vertices={1,2,3,4}
Edge={{1,2},{1,3},{1,4,},{2,4},{3,4}}
有向图:
有向图的边有箭头
Vertices={1,2,3,4}
Edges=({1,2},{1,3},{3,4})
Graph=({1,2,3,4},{1,2},{1,3},{3,4})
当有向图的序对改变了,图就变了
图就变成了Graph=({1,2,3,4},{4,3},{3,1},{1,2})
树形图也是图,比如HTML的结构、二叉树
三、Query(查询)&Mutation(修改)
这里是Git上面的一个API,可以进行简单的使用https://developer.github.com/v4/explorer/,需要先登录才可以。
1、GraphQL VS SQL
SQL查询数据库;GraphQL查询API
SQL的数据存在数据表里;GraphQL的数据可以存放在任何地方
SQL使用SELECT查询数据;GraphQL使用Query
SQL使用INSERT、UPDATE、DELETE来修改数据;GraphQL使用Mutation修改数据
GraphQL还可以进行订阅(通过socket)
2、查询Query
GraphQL的请求,GraphQL查询的内容通过HTTP POST的Body发送给GraphQL端点。
查询就是从API获取数据,它表示了你想从GraphQL服务器获取的数据;通过字段(field)来请求查询的数据;这些字段和查询结果的JSON响应的字段对应。
GraphQL查询错误:
成功查询的JSON结果里面包含一个data字段,不成功的查询结果里面包含一个errors字段,里面有具体的错误信息。JSON相应结果可同时包data和errors字段。
errorTest这个地段是吧存在的,所以在后面会包含一个errors字段,里面有具体的错误信息。
Query是GraphQL的一个类型,叫做根类型,因为它映射的事一个操作,而操作则代表着查询文档的根节点。
查询可用的字段是在schema里面定义的;可用查看文档
使用ALT+Space,可用显示参数
GraphQL修改和查询很像,就是意图不同。
GraphQL字段类型:
Scalar Type:Int、String、Float、Boolean、ID
Object Type
GraphQL片段Fragments
Fragments就是可用服用的选择集
片段(Fragments):
假设我们的app有比较复杂的页面,讲正反派主角及其友军分为两拨。你立马就能想到对应的查询会变得复杂,因为我们需要将一些字段重复至少一次——两房各一次作比较。
这就是为何GraphQL包含了称作片段的可复用单元,片段使你能够阻止一组字段,然后在他们需要的地方引入,下面的例子展示了如何使用片段解决上述场景:
GraphQL联合类型Union Type
如果你想返回不止一种类型,那么您可以使用Union Type
GraphQL接口Interface
2、修改Mutation
Mutation也是根对象类型,Mutation和Query很像,有名字、可以有返回的选择集,不同之处就是Mutation会修改后台数据的状态。
GraphQL查询变量:
代替写死的参数值,可以动态赋值,使用$开头。
3、订阅Subscription
Subscription允许我们监听GraphQL API的实时数据变化,Subscription也是根类型,通过WebSocket,与Query和Mutation不同,Subscription保持链接打开状态,如果想停止监听,需要取消订阅。
4、内省Introspection
一个非常强大的特性,Introspection可以让你查询当前API的schema,查询可用类型:_schema,查询类型明细:_type
5、抽象语法树Abstract Syntax Trees
抽象语法树AST,查询文档是字符串,查询时被解析成AST,并在每个操作运行前进行严重,AST是要给层次结构的对象,代表了查询,每一个操作都会被解析成AST(很重要)
四、Schema和Types
1、Schema是什么
GraphQL会改变你进行设计的过程,使用REST的时候,可以把你的API看作是一组REST端点,而在GraphQL里你把你的API看作成是一组类型,为你暴露的API定义的这组数据类型就叫做Schema。
设计Schema:
Schema First:使前后端团队在数据类型上保持一致
GraphQL使用SDL(Schema Definition Language)语言来定义Schema,无论使用什么开发语言或者框架GraphQL的SDL都是一样的,GraphQL的Schema就是定义了可用类型的文本文档,它被客户端和服务器端来验证GraphQL请求。
2、定义Types
GraphQL Schema的核心就是类型(Type),一个类型代表着一个自定义的对象,而这些对象则代表 了你的核心特征,类型有字段(Field),它代表了关联每个对象的数据,每个字段都会返回一个特定的数据类型。Schema就是类型定义的集合,Schema定义文件的后缀名通常是.graphql
类型定义:
例子:叹号表示不能为null
Scalar Type标量类型:
内置Int、Float、String、Boolean、ID
可以自定义Scalar Type,Scalar Type不是对象类型,它没有字段,例如:
Enum枚举类型:
枚举类型也是标量类型,它可以返回一组字符串中的一个值,例如:
3、Connections和List
创建Schema时,可以定义返回一个由任意Graph类型组成的列表,例如:[String]、[User],列表页可以由不同的类型组成,使用Union Type或者Interface Type,[Int]、[Int!]、[Int]!、[Int!]!的区别
一对一连接
图论里,两个对象之间的连接叫做边(Edge),而由一个对象连接到另外一个对象的连接就是一对一的连接
一对多连接
要尽量报纸GraphQL服务的无向性,也就是说可以从图的任何一个定点开始遍历;针对上例,添加一条从User类型回到Photo的路径:
多对多连接
例如标签操作Tagging
多对多连接,需要在双方类型里都添加List字段,一个多对多连接由两个一对多连接组成
创建多对多连接时,由时需要保存关系本身,这时就需要通过类型(Through Type),把边(Edge)定义为一个自定义对象类型,相当于连接两个节点的节点。由不同类型组成边的列表,GraphQL里的列表不一定非得是同一种理性,使用Union Type,Interface结合Fragment可以达到此目的。
Union Type
Union Type,我们可以用它返回多种类型中的一种类型
Interface:
为了保证某些类型必须包含特定的字段,我们可以使用接口Interface
4、Arguments参数
GraphQL里的任何字段都可以由Arguments,Arguments必须有类型,这个类型应该是hischema中已经定义好的标量类型或者对象类型
过滤数据:
Arguments吧一定非得是费控的,使用可控字段可以添加可选参数(optional arguments/optional parameters)
翻页;
要实现翻页功能至少需要两个可选参数(optional arguments),首先需要设定当前页一次性返回的条目数(first、pageSize.....),然后还要设定从哪个位置开始获取这些数据(start,pageIndex......)
排序:
方法有很多,可以使用enum来决定哪个字段可以用来排序
5、Mutation修改
Mutation也在schema里面定义,技术上Mutation和Query没有区别,只是他们的意图不同,Mutation是用来修改状态的,Mutation的名称里应该包含动词。
6、Input Types输入类型
Query和Mutation的参数可能会很多,这时最好使用Input Type来整理单数(arguments),Input Type和GraphQL里的对象类型很像,但是它只能用作输入参数,Input Type可以用作于任何子墩
7、Return Types返回类型
Schema里所有的字段都可以返回定义好的主类型,但有时候需要返回一些关于查询和修改的元信息,这时就可以创建一个返回类型。
8、Subscription订阅
Subscription类型和GraphQL的SDL里的其他类型也没有什么区别,在自定义对象类型的子墩上定义可用的Subscriptions。Subscription可用有参数
9、Schema文档
编写Schema的时候,可以为每个字段添加一些描述