GraphQL简介
GraphQL是Facebook开源的一套用于API的查询语言和runtime,其比较明显的特色在于用一次请求拿到所有想要的数据,并且返回的查询结果与想要查询的格式一致。同时也强调了强类型,减少冗余。
Query/Mutation
(后文大部分例子皆来自/魔改自官方文档)
拿一个如下的简单的query来分析,这里的hero,name或者friends叫做field
,field会返回type中定义的类型。
- field能通过例如
hero(name: "R2-D2")
这样的方式来添加参数 - 多个同级同类型的field能通过例如
empireHero: hero
来指定别名 - 多个filed要查询相同类型的数据时,可以用碎片(fragments)来复用相同的查询条件
- 当遇到多个查询需要带上不同的参数时,可以使用变量
可以用指令(directive)去动态的改变query的结构和形状,如
@include(if: Boolean)
@skip(if: Boolean)
12345678query Hero($episode: Episode, $withFriends: Boolean!) {hero(episode: $episode) {namefriends @include(if: $withFriends) {name}}}GraphQL不只是提供了获得数据的方式,也提供了Mutation去修改服务端的数据
123456mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {createReview(episode: $ep, review: $review) {starscommentary}}GraphQL的schemas能定义接口和结合(union)的type,因此当query中的field在schema中对应这些type时,你需要内联碎片(inline fragments)去获取混合(concrete)type之下的数据。
- 当不知道服务器返回的type时,可以用meta field去代替,即在field前加上
__
例如 我们要查询带有’an’的数据,同时也不知道返回的数据的type,如果这个返回的数据的type是Droid,则会同时返回primaryFunction,如果为Human类型,则会返回height。此外返回结果里的__typename就会是这个查询结果的type的名字了(此例中可能为Human、Droid或者Starship)1234567891011121314{search(text: "an") {__typename... on Human {height}... on Droid {primaryFunction}... on Starship {name}}}
Types/Schemas
上一节中提到了许多次type,type
即我们想要查询的field的类型,用于描述我们想要的数据。属于schema中最基础的一类
每一个GarphQL Service
定义了一系列的type用于完全描述一系列可能会被查询到的数据。当query来的时候,GraphQL Service会根据schema去验证并执行。
GraphQL Service可以用任何语言
去编写。同时还有一种叫做”GraphQL schema language”的语言用于描述schema。
一个简单的定义名为Character的type的例子
- name,appearsIn和length为该type的field
- field的type后面的!表示该field不可为null
- appearsIn: [Episode]表示对应这个appearsIn对应的是一个Episode类型的数据的数组
- schema中的参数必须有名字,等号前的为参数的type,后面的为默认值
一些基本的type:
Int
Float
String
Boolean
ID
12345type Character {name: String!appearsIn: [Episode]!height(unit: LengthUnit = METER): Float}纯量(scalar):经常作为query的叶结点,例如最前面的query例子里的name。可以用scalar去声明一个纯量
scalar Date
枚举(enum):枚举是一种特殊的纯量,他被限制为一个特定允许值的集合。这个特性可以拿来做验证或者利用一个有限集合的值来在type系统之间传送,可以用如下方式声明,Episode一定会为NEWHOPE、EMPIRE、和JEDI其中之一
12345enum Episode {NEWHOPEEMPIREJEDI}接口(interface):像许多强类型语言一样,GraphQL也提供了接口,即包含了type必须实现的、确定的、field的集合的抽象的type。
1234567891011121314interface Character {id: ID!name: String!friends: [Character]appearsIn: [Episode]!}type Human implements Character {id: ID!name: String!friends: [Character]appearsIn: [Episode]!starships: [Starship]totalCredits: Int}结合(union):结合和接口非常类似,只是没有具体说明type之间的共同field,即没有将type的具体属性抽象出来
1union SearchResult = Human | Droid | Starship输入(input):当你可能要传递整个对象(例如参数为一个对象时),需要指定这个对象的type,就可以使用input。简单的把type换成input即可
1234input ReviewInput {stars: Int!commentary: String}
上面就是GraphQL中一些基础概念,更加进阶的概念会在以后的文章中提到。
GraphQL对比RESTful
一万个人心中有一万种RESTful,RESTful虽然简单易理解,但是在深入开发的过程中其难扩展的缺点逐渐暴露了出来。
例如前面官网上的例子,GraphQL会直接返回这样的结果
而RESTful,可能有人会这样写
或者
这种情景下,RESTful可能会去发送多次请求,或者把请求魔改得不直观。GraphQL恰恰能很好的解决这类问题。
同时我们也看到了,GraphQL在一定程度上,查询请求是不依赖url的,这也许意味着当系统要添加新的功能,同时需要的数据能用之前的数据组装,就不需要新的后台接口了。
此外,若是后台能将数据拆分,提供大量的原子数据接口的话,那么对于产品版本迅速迭代将是一件非常有意义的事情。
Relay简介
Relay是一个用于构建数据驱动的React应用的框架,结合GraphQL可以实现用GraphQL声明需要的数据,Relay指明在什么时机用什么方法去获取数据。
Relay还能综合所有query,利用高效的网络请求去获取你恰好需要的数据,也能结合GraphQL的mutation去修改客户端/服务端上的数据,并且同时提供了自动化的连贯的数据更新机制和错误处理机制。