使用Lighthouse轻松驾驭Laravel + GraphQL的接口类型和联合类型
因为在实现Lighthouse的Interface和Union时遇到了一些困难,而且对于这些问题的相关信息进行了调查但却找不到任何结果,所以我写了一篇文章。
环境
PHP版本为7.2.5
Laravel版本为7.0
Lighthouse版本为4.13
界面类型
GraphQL 中的接口与 Java 或 PHP 中的抽象字段类似,要求接口定义的字段也必须在继承该接口的类型中提供。
在继承了Interface的Type中,可以自由添加除此之外的其他值。
GraphQL: 模式和类型#接口
interface Animal {
id: ID!
name: String!
}
type Cat implements Animal {
id: ID!
name: String!
feed: String
}
type Dog implements Animal {
id: ID!
name: String!
favorite: [DogItem!]!
}
type DogItem {
id: ID!
name: String
}
使用Interface Type的好处是可以将它本身指定为查询或变更的参数或返回值。
假设我们定义了一个查询,可以返回以下动物的列表。
type Query {
animals: [Animal!]!
}
如果执行此操作,将获得以下Cat和DogType混合的响应。
query {
animals {
id
name
__typename
... on Cat {
feed
}
... on Dog {
favorite {
id
name
}
}
}
}
{
"data": {
"animals": [
{
"id": "1",
"name": "hoge_cat",
"__typename": "Cat",
"feed": "pet_food"
},
{
"id": "2",
"name": "fuga_dog",
"__typename": "Dog",
"favorite": [
{
"id": "1",
"name": "ball"
}
]
},
{
"id": "3",
"name": "piyo_cat",
"__typename": "Cat",
"feed": "cat_food"
}
]
}
}
实施的注意事项
灯塔:界面种类
在使用Lighthouse实现接口时,通常不能使用常规的指令(例如@all或@create),而需要使用解析器来实现。
$ php artisan lighthouse:query AnimalResolver
type Query {
animals: [Animal!]! @field(resolver: "App\\GraphQL\\Queries\\AnimalResolver@list")
}
同名的Cat和Dog模型也会创建,它们都继承自Interface。
此时,如果使用数组或不同名称的模型,将会触发错误:basename()期望第一个参数为字符串,但给出的是数组,所以请注意。
$ php artisan make:model Cat
$ php artisan make:model Dog
class AnimalResolver
{
public function list($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
{
$hoge_cat = new Cat;
$hoge_cat->id = 1;
$hoge_cat->name = 'hoge_cat';
$hoge_cat->feed = 'pet_food';
$fuga_dog = new Dog;
$fuga_dog->id = 2;
$fuga_dog->name = 'fuga_dog';
// ※Interfaceを継承していない通常のTypeは配列でも問題ない。
$fuga_dog_item = [
'id' => 1,
'name' => 'ball'
];
// モデルを使用する場合は以下のようにする。
// $fuga_dog_item = new DogItem;
// $fuga_dog_item->id = 1;
// $fuga_dog_item->name = 'ball';
$fuga_dog->favorite = [$fuga_dog_item];
$piyo_cat = new Cat;
$piyo_cat->id = 3;
$piyo_cat->name = 'piyo_cat';
$piyo_cat->feed = 'cat_food';
return [
$hoge_cat,
$fuga_dog,
$piyo_cat
];
}
}
工会
Union Type是一种抽象类型,其简单地列举了其他类型。然而,与接口不同的是,它不能定义字段。
GraphQL:模式和类型#联合类型
union Book = Novel | Comic
type Novel {
novel_title: String!
}
type Comic {
comic_title: String!
}
在处理查询时,可以通过使用”on”关键字来指定每种类型的响应,就像处理接口一样。
type Query {
books: [Book!]!
}
query {
books {
__typename
... on Novel {
novel_title
}
... on Comic {
comic_title
}
}
}
{
"data": {
"books": [
{
"__typename": "Novel",
"novel_title": "hoge title"
},
{
"__typename": "Comic",
"comic_title": "comic title"
}
]
}
}
在实施过程中的注意事项
灯塔:类型 #联盟
使用Union时,无法使用常规的指令,因此需要使用Resolver,就像Interface一样。
同样需要注意的是,如果不使用Model对象处理响应类型,将会产生错误。
class BookResolver
{
public function list($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
{
$novel = new Novel;
$novel->novel_title = 'hoge title';
$comic = new Comic;
$comic->comic_title = 'fuga title';
return [
$novel,
$comic
];
}
}
参考书目
GraphQL: 模式和类型
Lighthouse: 类型