和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更適合用來實現開放接口。