GraphQL解析粒度
引言
关于GraphQL的基础概念,可以参看前一篇文章《更轻松的使用GraphQL》。
困惑
初次看到GraphQL,很容易被它强大的介绍所吸引,但想更进一步尝试时,却会发现它的”hello world“不是很友好,容易让人打退堂鼓。
我们首先看一下官方(grpahql-js)的例子:
var schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {
type: GraphQLString,
resolve() {
return 'world';
}
}
}
})
});
其中,resolve函数定义部分,换成更直观一些的写法(伪代码)就是:
{
// 每个field独立的resolve函数
hello: function resolve () {
return 'world';
}
}
这就让人很害怕了,一个数据结构中的每个成员都要定义一个resolve函数的话,工作量和开发复杂度就令人难以接受了,所以很多人看了官方README就被吓退了。
但实际上,GraphQL是可以整个对象使用一个resolve函数来获取所有field的数据,看伪代码大概就是:
{ // 整个对象使用一个resolve函数
hello,
xxx,
foo,
...
} : function resolve () {
return {
hello : "world",
foo : "bar",
...
};
}
实战
我们还是以论坛帖子为例:
1. schema定义
用户定义:
# user schema
type User {
uid : ID!
name : String!
avatar : String!
}
帖子定义:
# post schema
type Post {
pid : ID!
title : String!
content : String!
author : User!
}
2. 提供的查询方法定义
查询定义:
type Query {
post(id: ID): Post
}
3. 对应的resolve函数编写
'use strict'
const fakeDB = require('../../fakeDB');
function fetchPostById (root, {id}, ctx) {
// post的查询,第二个参数是查询语句中传入的
let pid = parseInt(id);
return fakeDB.getPostById(pid);
}
// 对post下的author字段进行查询解决的函数
function fetchUserByAuthorId (root, args, ctx) {
// 执行完post的数据查询后,遇到需要author字段的情况,会再来调用本函数,root参数就是前一步查询完的post数据
let uid = root.authorId;
return fakeDB.getUserById(uid);
}
const postReolvers = {
Query : {
post : fetchPostById,
},
Post : {
// 针对嵌套的数据结构需要的解决函数
author : fetchUserByAuthorId,
},
};
module.exports = postReolvers;
4. 查询的结果
通过上面的fetchPostById
函数,就能查询指定id的帖子详情(整个Post数据结构)了,而无需对Post的每个field分别定义resolve函数:
查询返回结果如下:
{
"data": {
"post": {
"pid": "1",
"title": "foo",
"content": "xxx",
"author": {
"uid": "1",
"name": "Tom",
"avatar": "https://pre00.deviantart.net/2930/th/pre/i/2014/182/a/2/tom_cat_by_1997ael-d7ougoa.png"
}
}
}
}
结语
希望本文能对大家初步了解GraphQL有所帮助,不要被官方“hello world”给吓退了,而能够去进一步尝试一下GraphQL。
欢迎使用更简单的GraphQL封装库:easy-graphql