和RESTfull一样,GraphQL也是一种基于HTTP的接口实现方式。它区别于前者的主要有两点:数据格式的自定义和请求的合并。

本质上,GraphQL是为了解决RESTful中前后端在业务逻辑上的耦合关系。在RESTful中,接口是为前端具体的业务需求定制的,从实现什么样的功能,到返回哪些数据,都是既定的,所以很难被其它业务逻辑共用,即使可以共用,前端也必须发送多个请求到后端,因而造成资源浪费、效率下降。

GraphQL实现的是一套逻辑积木,每个封装好的业务逻辑都是原子的,前端可以自由选择使用哪些,也可以定制返回数据的格式。并且这一切,都可以通过一次请求实现。

当然,GraphQL也有一些短板。比如缓存,对于RESTfull接口,可以根据操作的幂等性实现负载均衡层面的缓存,而对于GraphQL,由于请求数据格式灵活且可能很大,请求会用POST方式发送,这样就必须改变缓存的实现方式。再一点是嵌套的层级问题,GraphQL的灵活性允许查询类型之间彼此嵌套,如果层级过多,可能导致严重的性能和可用性问题,因此需要注意限制嵌套的层级。还有就是GraphQL的实现复杂度比RESTful要高,需要权衡使用哪种实现方案。

GraphQL用schema管理接口,可以根据业务等因素划分schema,例如需要权限验证的和公开的。每个schema包含两类接口:query和mutation,分别用来查询和变更数据。

下面在Laravel中简单实现一个query接口。

先安装folklore/graphql库。

实现文章类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
namespace App\GraphQL\Type;

use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as GraphQLType;

class PostType extends GraphQLType {

public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the post'
],
'title' => [
'type' => Type::string(),
'description' => 'Post title'
]
];
}

protected function resolveTitleField($root, $args)
{
return $root->post_title;
}

}

实现文章的查询逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace App\GraphQL\Query;

use GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Query;
use App\Models\Post;

class PostQuery extends Query {

public function type()
{
return Type::listOf(GraphQL::type('Post'));
}

public function resolve($root, $args)
{
if(isset($args['id'])) {
return Post::where('id' , $args['id'])->get();
} else {
return Post::all();
}
}

}

config/graphql.php中注册类型和逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
'schemas' => [
'default' => [
'query' => [
'posts' => 'App\GraphQL\Query\PostQuery'
],
'mutation' => [

]
],
],

'types' => [
'Post' => 'App\GraphQL\Type\PostType',
],

请求及结果如下:

GraphQL并不是RESTful的替代方案,是否用前者替代后者,取决于是否愿意为了灵活性而增加复杂度。两者有各自的适用领域,GraphQL更适合用来实现开放接口。