概述
GraphQL
是由FaceBook
开发的一种API查询语言,调用者可以无任何冗余的情况下获取到数据。
与GraphQL
对标的是Rest
:
Rest
是由后台定义返回的字段,如果后台返回的字段过多,则会出现返回的无用字段影响性能,如果后台返回的字段不足,则需要后台重新开发新增需要的字段GraphQL
是由调用者定义需要返回的字段,后台根据请求返回指定字段
学习资料
官方文档中文:https://graphql.bootcss.com/learn/
官方文档英文:https://graphql.org/learn/
官方文档的资料写的很详细也非常浅显易懂,我下面也只是搬运核心的一些内容。
(顺口一提)官方文档里面的示例是可以直接修改运行的
schema
中文文档:https://graphql.bootcss.com/learn/schema/
英文文档:https://graphql.org/learn/schema/GraphQL
是由schema文件来定义所提供的能力,简单理解就是用schema来定义有哪些接口,接口对应的请求结构体和响应接口体
官方文档上并没有给出示例的starwar
的schema文件,含义也没有做解释,我这里稍微做一下补充,如下:
# The query type, represents all of the entry points into our object graph
type Query {
hero(episode: Episode = NEWHOPE): Character
reviews(episode: Episode!, since: Time): [Review!]!
search(text: String!): [SearchResult!]!
character(id: ID!): Character
droid(id: ID!): Droid
human(id: ID!): Human
starship(id: ID!): Starship
}
# The mutation type, represents all updates we can make to our data
type Mutation {
createReview(episode: Episode!, review: ReviewInput!): Review
}
# A humanoid creature from the Star Wars universe
type Human implements Character {
# The ID of the human
id: ID!
# What this human calls themselves
name: String!
# Height in the preferred unit, default is meters
height(unit: LengthUnit = METER): Float!
# Mass in kilograms, or null if unknown
mass: Float
# This human's friends, or an empty list if they have none
friends: [Character!]
# The friends of the human exposed as a connection with edges
friendsConnection(first: Int, after: ID): FriendsConnection!
# The movies this human appears in
appearsIn: [Episode!]!
# A list of starships this person has piloted, or an empty list if none
starships: [Starship!]
}
# An autonomous mechanical character in the Star Wars universe
type Droid implements Character {
# The ID of the droid
id: ID!
# What others call this droid
name: String!
# This droid's friends, or an empty list if they have none
friends: [Character!]
# The friends of the droid exposed as a connection with edges
friendsConnection(first: Int, after: ID): FriendsConnection!
# The movies this droid appears in
appearsIn: [Episode!]!
# This droid's primary function
primaryFunction: String
}
# A connection object for a character's friends
type FriendsConnection {
# The total number of friends
totalCount: Int!
# The edges for each of the character's friends.
edges: [FriendsEdge!]
# A list of the friends, as a convenience when edges are not needed.
friends: [Character!]
# Information for paginating this connection
pageInfo: PageInfo!
}
# An edge object for a character's friends
type FriendsEdge {
# A cursor used for pagination
cursor: ID!
# The character represented by this friendship edge
node: Character
}
# Information for paginating this connection
type PageInfo {
startCursor: ID!
endCursor: ID!
hasNextPage: Boolean!
}
# Represents a review for a movie
type Review {
# The number of stars this review gave, 1-5
stars: Int!
# Comment about the movie
commentary: String
# when the review was posted
time: Time
}
# The input object sent when someone is creating a new review
input ReviewInput {
# 0-5 stars
stars: Int!
# Comment about the movie, optional
commentary: String
# when the review was posted
time: Time
}
type Starship {
# The ID of the starship
id: ID!
# The name of the starship
name: String!
# Length of the starship, along the longest axis
length(unit: LengthUnit = METER): Float!
# coordinates tracking this ship
history: [[Int!]!]!
}
# The episodes in the Star Wars trilogy
enum Episode {
# Star Wars Episode IV: A New Hope, released in 1977.
NEWHOPE
# Star Wars Episode V: The Empire Strikes Back, released in 1980.
EMPIRE
# Star Wars Episode VI: Return of the Jedi, released in 1983.
JEDI
}
# A character from the Star Wars universe
interface Character {
# The ID of the character
id: ID!
# The name of the character
name: String!
# The friends of the character, or an empty list if they have none
friends: [Character!]
# The friends of the character exposed as a connection with edges
friendsConnection(first: Int, after: ID): FriendsConnection!
# The movies this character appears in
appearsIn: [Episode!]!
}
# Units of height
enum LengthUnit {
# The standard unit around the world
METER
# Primarily used in the United States
FOOT
}
union SearchResult = Human | Droid | Starship
scalar Time
类型 | 含义 | 示例 |
---|---|---|
! | 标识该字段非空 | |
[[]](https://graphql.bootcss.com/l...) | 表示当前字段为数组类型 | |
Query | 对外提供查询的接口,类似于rest中的get请求,括号中为请求结构体,最后字段响应结构体 | 上文中Query 的hero 为例,请求参数名为episode ,请求类型为Episode ,如果不传参,默认值为NEWHOPE ,响应类型为Character |
Mutation | 对外提供的插入接口,类似于rest中的put请求,括号中为请求结构体,最后字段响应结构体 | 上文中Mutation 的createReview 为例,请求参数名为episode 和review ,请求类型为Episode 和ReviewInput ,且都不能为空,响应类型为Review |
type | 结构体,定义GraphQL 中所需要的结构体 | 上文中的Human 为例,定义了id ,name ,height 等字段,类型ID ,String ,Float ,Boolean , Int 为GraphQL 自身提供的类型,字段也可以有查询参数。比如height 字段有参数unit ,类型为LengthUnit ,默认值为METER |
interface | 接口类型,其实我觉得理解成超类或者父类更合适,就是定义了其他类型所共有的字段 | 上文中Character 为例,Droid 和Human 都实现(继承)了Character 的属性,这里的子类需要重新声明Character 的字段 |
enum | 枚举类型 | 上文中Episode 为例,定了三个值NEWHOPE ,EMPIRE ,JEDI ,枚举的类型这里不会体现,可以在实现的时候自定义,通常是字符串类型 |
input | 定义接口的请求参数类型,该类型字段只能用户接口的入参 | 上文中ReviewInput 为例,在Mutation 中的createReview 的入参为ReviewInput 类型 |
union | 联合类型,和接口十分相似,但是它并不指定类型之间的任何共同字段。 | 上文中SearchResult 为例,该字段既可以是Human ,也可以是Droid ,或者Starship ,在实现的时候可以解析指定类型 |
scalar | 定义标量类型,GraphQL 中默认的标量为ID ,String ,Float ,Boolean , Int ,实现的时候需要实现类型的序列化,反序列,验证等方法 | 上文中Time 为例,定义全新的标量,对应的解析方法需要在代码实现 |
查询
中文文档:https://graphql.bootcss.com/learn/queries/
英文文档:https://graphql.org/learn/queries/
建议去上面的网址去运行一下脚本,实地感受一下效果
query testQueryHuman{
human1000:human(id: "1000") {
name
height(unit: FOOT)
}
human1001:human(id: "1001") {
name
height
}
}
得到的效果:
{
"data": {
"human1000": {
"name": "Luke Skywalker",
"height": 5.6430448
},
"human1001": {
"name": "Darth Vader",
"height": 2.02
}
}
}
1、可以看到查询几个字段就返回几个字段
2、query testQueryHuman
为当前查询的操作名称,query
为固定资,后面的名字自定义
3、human1000
和human1001
为查询结果的别名,可以不写
4、id: "1000"
和id: "1001"
为查询参数,即查询ID为1000和1001的人类,同时可见查询的字段height
也是可以带参数的
5、其他的操作,如片段,指令,变更,内联片段见官方文档
我理解的优缺点
优点:
- 由调用者决定返回的数据,数据足够透明
- 降低网络带宽,提供相应速度
- 减少服务的开发成本,更加适应多变的需求
缺点:
- 系统整体架构复杂化,毕竟多引入了组件
- 后台系统复杂度上升,数据层对数据的维护和提供能力需要增强,因为原本只需要查询少量字段,现在需维护所有需要的字段,以备调用者请求
- 对调用者而言,学习成本更大,本来只需要了解接口字段含义,现在需要了解整个
GraphQL
提供的能力
实现
GraphQL
提供了多种语言的实现代码库,详情可见https://graphql.bootcss.com/code/
java的之前玩过了,也写过一下文档,可见https://blog.csdn.net/q15150676766/category_7004424.html但是有点年久失修了
这次主要研究的是GO
使用GraphQL
的框架,GO
提供的框架太多了,学习起来有点吃力,这次主要学习和研究最火的三个(也是就star最多的三个),我们项目中用的是gqlgen
,太高级的功能没做深究,粗浅的学习一下怎么用。
- graphql-go:一个 Go/Golang 的
GraphQL
实现 - graph-gophers/graphql-go:一个活跃的 Golang
GraphQL
实现 - 99designs/gqlgen:生成基于
GraphQL
的服务器的库
下面是大佬们整理的三个框架的比较
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。