graphQL与传统的Reatful API相比的优势:
-
graphQL只返回我们需要的数据,Reatful API返回冗余数据
-
Reatful API在同一个url节点下的不同资源要发送不同的请求
/users/:id /users/posts
对象类型和字段
在Graph中大多数类型是对象类型:
{
hero {
name
appearsIn
}
}
- 外层的大括号是root Object
- 选取了对象中的hero字段
- 选取hero字段返回的对象中的name和appearsIn字段
在服务器端:
type Character{
name:String!
appearsIn:[Episode!]!
}
- Character 对象类型,指的是有字段的类型
- name appearsIn 在Character 中的类型,在Character 类型的查询中,name和appearsIn是唯一会返回的字段
- String 内置的标量类型,会被解析成单一的标量对象
- String! 服务端承诺每当查询这个字段就会返回值
- [Episode!]! 指的是一个由Episode对象组成的数组。每当查询appearsIn字段时,就会返回一个由Episode对象组成的数组
但是在Schema中,有2个特殊类型:Query和Mutation类型,特殊在于它们定义每个查询的入口节点。
每个GraphQL服务器都有query类型,不一定有mutation类型
Query获取数据
参数可以决定返回多少数据,只要最后2条数据
allPersons(last:2){
name,
age
}
客户端发送如下请求:
query{
hero{
name
}
droi(id:"2000"){
name
}
}
意味着服务器端有Query类型,其中有hero和droi字段
type Query {
hero(episode:Episode):Character
droi(id:ID!):Droi
}
Mutation同理
Mutations
创建,修改,删除数据就用mutation
mutation {
createPerson(name:"Bob",age:36){//创建了一个人,并传入参数
id//让服务器返回的东西 id是服务器自动生成的
//可以在此获取修改后的数据
}
}
Subscriptions
用Subscriptions实现客户端和服务器实时连接
当客户端订阅一个事件:发送subscription给服务端,客户端就和服务器维持了一个持久连接,不管该事件是否发生,当数据变动时,服务端都会推送响应数据给客户端。而不需要客户端发送请求。
每当mutation修改、更新、创建数据,服务器就会把新的数据推送给客户端
type Query {
allPersons:[Person!]!
}
type Mutation {
createPerson(name: String!, age: Int!): Person!
}
type Subscription {
newPerson: Person!
}
Schema(模式)
GraphQL有自己的类型语言,Schema就是用来定义类型的模式,指定客户端如何请求数据,代表客户端和服务端之间的契约
type User{
id:ID!
name:String
}
定义了User类型,但是它不能给客户端提供任何功能,要给客户端提供功能,需要给类型添加根类型:Query、Mutation、Subscription
Schema根类型决定了哪些query和mutation能够被服务器接收,是服务器能力的抽象描述
//客户端才能够发送以下请求
query{
user(id:"abc"){
id
name
}
}
//只有在Schema中定义了有Query根节点的user字段
type Query{
user(id:ID!):User
}
执行Query的原理
query请求只是一组字段,当服务器接收到query请求的时候,就会根据这些字段调用响应的解析器函数
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
user: {
type: UserType,
args: {
id: { type: GraphQLID },
},
resolve: (root, args, context, info) => {
const { id } = args // the `id` argument for this field is declared above
return fetchUserById(id) // hit the database
},
},
},
}),
})
const UserType = new GraphQLObjectType({
name: 'User',
fields: {
id: {
type: GraphQLID,
resolve: (root, args, context, info) => {
return root.id
},
},
name: {
type: GraphQLString,
// (root, args, context, info) 分别代表
//root 父节点,是上一次调用resolver函数的结果;
//args 请求参数
//context 解析器通信的方法
//info 查询或变更的AST表示
resolve: (root, args, context, info) => {
return root.name
},
},
},
})
嵌套多层的请求,可以用dataLoader来做性能优化