resolve function
再回到刚开始的 hello, world 的示例,用 graphql 表示如下
# schema
type Query {
hello: String
}
# query
query HELLO {
hello
}
对以上章节的内容再梳理一遍:
- 可以对
hello进行查询,因为该字段在Query下 HELLO查询所得到的data.hello是一个字符串
恩?我们好像把最重要的内容给漏了,hello 中的内容到底是什么?!而 resolve 函数就是做这个事的
// 使用 graphql.js 的写法,把 schema 与 resolve 写在一起
new GraphQLObjectType({
name: "RootQueryType",
fields: {
hello: {
type: GraphQLString,
resolve() {
return "hello, world";
},
},
},
});
// 单独把 resolve 函数给写出来
function Query_hello_resolve() {
return "hello, world";
}
于是我们再补齐以上内容
# schema
type Query {
hello: String
}
# query
{
hello
}
由此得到的数据示例
{
hello: "hello, world";
}
context 与 args
查看一个很典型的 REST 服务端的一段逻辑:抽取用户ID以及读取参数(querystring/body)
app.use('/', (ctx, next) {
ctx.user.id = getUserIdByToken(ctx.headers.authorization)
next()
})
app.get('/todos', (ctx) => {
const userId = ctx.user.id
const status = args.status
return db.Todo.findAll({})
})
而在 graphql 中,使用 resolve 函数为 field 提供数据,而 context,args 都会作为 resolve 函数的参数
# schema
type Query {
# 如同 REST 一般,可以携带参数,并显式声明
todos(status: String): [Todo!]!
}
type Todo {
id: ID!
title: String!
}
# query
{
# 查询时,在这里指定参数 (args)
todos(status: "TODO") {
id
title
}
# 同时也可以指定别名,特别是当有 args 时
done: todos(status: "DONE") {
id
title
}
}
# query with variables
query TODOS($status: String) {
done: todos(status: $status) {
id
title
}
}
返回数据示例
{
todos: [{ id: 1, title: '松风吹解带' }],
done: [{ id: 2, title: '山月照弹琴' }],
}
当然,我们也是通过 Query 以及 Todo 的 resolve 函数来确定内容,对于如何获取以上数据如下所示
// Query 的 resolve 函数
const Query = {
todos(obj, args, ctx, info) {
// 从 ctx 中取一些上下文信息,如最常见的 user
const userId = ctx.user.id;
const status = args.status;
return db.Todo.findAll({});
},
};
// Todo 的 resolve 函数
const Todo = {
title(obj) {
return obj.title;
},
};
- obj,代表该字段所属的
object type,如Todo.title中obj表示todo - args,代表所传过来的参数
- ctx,上下文
- info,
GraphQLResolveInfo,关于本次查询的元信息,比如 AST,你可以对它进行解析
从这里可以看出来:graphql 的参数都是显式声明,并且强类型。这一点比 REST 要好一些
# query with variables
query TODOS($status: String) {
done: todos(status: $status) {
id
title
}
}