原文地址:
使用
语法 / Schemas
从 1.0 版本开始, 可以定义多个语法, 如果您想要一个公共的入口,另一个需要身份验证的入口,那么拥有多个语法是非常有用的。
您可以在配置中定义多个语法:
'schema' => 'default',
'schemas' => [
'default' => [
'query' => [
//'users' => 'App\GraphQL\Query\UsersQuery'
],
'mutation' => [
//'updateUserEmail' => 'App\GraphQL\Query\UpdateUserEmailMutation'
]
],
'secret' => [
'query' => [
//'users' => 'App\GraphQL\Query\UsersQuery'
],
'mutation' => [
//'updateUserEmail' => 'App\GraphQL\Query\UpdateUserEmailMutation'
]
]
]
或者可以使用 facade 来添加语法
GraphQL::addSchema('secret', [
'query' => [
'users' => 'App\GraphQL\Query\UsersQuery'
],
'mutation' => [
'updateUserEmail' => 'App\GraphQL\Query\UpdateUserEmailMutation'
]
]);
随后, 你可以使用 facade 来创建语法
// Will return the default schema defined by 'schema' in the config
$schema = GraphQL::schema();
// Will return the 'secret' schema
$schema = GraphQL::schema('secret');
// Will build a new schema
$schema = GraphQL::schema([
'query' => [
//'users' => 'App\GraphQL\Query\UsersQuery'
],
'mutation' => [
//'updateUserEmail' => 'App\GraphQL\Query\UpdateUserEmailMutation'
]
]);
你可以通过指定的语法来访问
// Default schema
http://homestead.app/graphql?query=query+FetchUsers{users{id,email}}
// Secret schema
http://homestead.app/graphql/secret?query=query+FetchUsers{users{id,email}}
创建查询
首先你需要创建一个类型
namespace App\GraphQL\Type;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as GraphQLType;
class UserType extends GraphQLType
{
protected $attributes = [
'name' => 'User',
'description' => 'A user'
];
/*
* Uncomment following line to make the type input object.
* http://graphql.org/learn/schema/#input-types
*/
// protected $inputObject = true;
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the user'
],
'email' => [
'type' => Type::string(),
'description' => 'The email of user'
]
];
}
// If you want to resolve the field yourself, you can declare a method
// with the following format resolve[FIELD_NAME]Field()
protected function resolveEmailField($root, $args)
{
return strtolower($root->email);
}
}
然后将类型添加到 config/graphql.php
文件中
'types' => [
'User' => 'App\GraphQL\Type\UserType'
]
你也可以使用 GraphQL Facade 来进行添加, 添加到 service provider 中
GraphQL::addType('App\GraphQL\Type\UserType', 'User');
然后, 你需要定义一个查询并且返回这个类型(或者列表). 你同样也可以在指定的参数, 这些参数可以用在 resolve 方法中.
namespace App\GraphQL\Query;
use GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Query;
use App\User;
class UsersQuery extends Query
{
protected $attributes = [
'name' => 'users'
];
public function type()
{
return Type::listOf(GraphQL::type('User'));
}
public function args()
{
return [
'id' => ['name' => 'id', 'type' => Type::string()],
'email' => ['name' => 'email', 'type' => Type::string()]
];
}
public function resolve($root, $args)
{
if (isset($args['id'])) {
return User::where('id' , $args['id'])->get();
} else if(isset($args['email'])) {
return User::where('email', $args['email'])->get();
} else {
return User::all();
}
}
}
添加 query 到 config/graphql.php
文件中
'schemas' => [
'default' => [
'query' => [
'users' => 'App\GraphQL\Query\UsersQuery'
],
// ...
]
]
这样就OK了, 你可以使用 /graphql
来进行查询了. 尝试使用 get 请求来获取下数据
query FetchUsers {
users {
id
email
}
}
或者使用 url 地址来进行请求
http://homestead.app/graphql?query=query+FetchUsers{users{id,email}}
创建修改
更改就是另外一种形式的查询, 他接受参数(用来进行更改或者创建使用的)并且返回一个对象或者指定的类型
例如使用修改来更新用户的密码, 首先你需要定义 mutation
namespace App\GraphQL\Mutation;
use GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Mutation;
use App\User;
class UpdateUserPasswordMutation extends Mutation
{
protected $attributes = [
'name' => 'updateUserPassword'
];
public function type()
{
return GraphQL::type('User');
}
public function args()
{
return [
'id' => ['name' => 'id', 'type' => Type::nonNull(Type::string())],
'password' => ['name' => 'password', 'type' => Type::nonNull(Type::string())]
];
}
public function resolve($root, $args)
{
$user = User::find($args['id']);
if (!$user) {
return null;
}
$user->password = bcrypt($args['password']);
$user->save();
return $user;
}
}
就想 resolve
方法. 你使用参数来更新你的模型并且返回她.
然后添加 mutation 到 config/graphql.php
文件中
'schema' => [
'default' => [
'mutation' => [
'updateUserPassword' => 'App\GraphQL\Mutation\UpdateUserPasswordMutation'
],
// ...
]
]
你可以使用如下的查询来进行修改
mutation users {
updateUserPassword(id: "1", password: "newpassword") {
id
email
}
}
url 中可以如下请求
http://homestead.app/graphql?query=mutation+users{updateUserPassword(id: "1", password: "newpassword"){id,email}}
添加修改验证
在修改中增加验证是可以的. 老铁. 它使用 laravel Validator
来处理验证并且返回相应的参数.
当创建 mutation 的时候, 你可以添加如下方法来定义验证规则:
namespace App\GraphQL\Mutation;
use GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Mutation;
use App\User;
class UpdateUserEmailMutation extends Mutation
{
protected $attributes = [
'name' => 'UpdateUserEmail'
];
public function type()
{
return GraphQL::type('User');
}
public function args()
{
return [
'id' => ['name' => 'id', 'type' => Type::string()],
'email' => ['name' => 'email', 'type' => Type::string()]
];
}
public function rules()
{
return [
'id' => ['required'],
'email' => ['required', 'email']
];
}
public function resolve($root, $args)
{
$user = User::find($args['id']);
if (!$user) {
return null;
}
$user->email = $args['email'];
$user->save();
return $user;
}
}
同样, 你可以在参数中定义规则:
class UpdateUserEmailMutation extends Mutation
{
//...
public function args()
{
return [
'id' => [
'name' => 'id',
'type' => Type::string(),
'rules' => ['required']
],
'email' => [
'name' => 'email',
'type' => Type::string(),
'rules' => ['required', 'email']
]
];
}
//...
}
当你执行修改的时候, 会返回验证错误. 由于 GraphQL 规范定义了错误的格式,因此会将验证错误消息作为额外的 validation
属性添加到错误对象中。为了找到验证错误,应该检查一个 message
等于 validation
的时候,然后 validation
属性将包含 Laravel Validator 返回的正常错误消息信息.
{
"data": {
"updateUserEmail": null
},
"errors": [
{
"message": "validation",
"locations": [
{
"line": 1,
"column": 20
}
],
"validation": {
"email": [
"The email is invalid."
]
}
}
]
}
高级用法
查询变量
GraphQL 允许你使用变量来查询数据, 从而不用在查询中硬编码值. 如下
query FetchUserByID($id: String) {
user(id: $id) {
id
email
}
}
当你查询 GraphQL 的时候可以传递 variables
参数
http://homestead.app/graphql?query=query+FetchUserByID($id:String){user(id:$id){id,email}}&variables={"id":"1"}
查询嵌入资源
如果想查询嵌入资源
query FetchUser{
user(id: 123456789) {
id
posts(id: 987654321) {
id
}
}
}
你需要在 UserType 中添加 post 字段并且实现 resolveField 方法
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'Id of user',
],
'posts' => [
'args' => [
'id' => [
'type' => Type::string(),
'description' => 'id of the post',
],
],
'type' => Type::listOf(GraphQL::type('Post')),
'description' => 'post description',
],
];
}
public function resolvePostsField($root, $args)
{
if (isset($args['id'])) {
return $root->posts->where('id', $args['id']);
}
return $root->posts;
}
枚举
美剧类型是一个特殊类型的标量变量, 用来限制一系列的允许的数据, 可以查看这里阅读更多的信息
首先创建一个 Enum 作为 GraphQLType 的扩展类型
<?php
// app/GraphQL/Enums/EpisodeEnum.php
namespace App\GraphQL\Enums;
use Folklore\GraphQL\Support\Type as GraphQLType;
class EpisodeEnum extends GraphQLType {
protected $enumObject = true;
protected $attributes = [
'name' => 'Episode',
'description' => 'The types of demographic elements',
'values' => [
'NEWHOPE' => 'NEWHOPE',
'EMPIRE' => 'EMPIRE',
'JEDI' => 'JEDI',
],
];
}
注册 Enum 在 config/graphql.php
的 types
数组
// config/graphql.php
'types' => [TestEnum' => TestEnumType::class ];
然后如下使用
<?php
// app/GraphQL/Type/TestType.php
class TestType extends GraphQLType {
public function fields()
{
return [
'type' => [
'type' => GraphQL::type('TestEnum')
]
]
}
}
接口
你可以使用接口来限制一系列的字段, 阅读更多的消息点击这里
一系列的接口
<?php
// app/GraphQL/Interfaces/CharacterInterface.php
namespace App\GraphQL\Interfaces;
use GraphQL;
use Folklore\GraphQL\Support\InterfaceType;
use GraphQL\Type\Definition\Type;
class CharacterInterface extends InterfaceType {
protected $attributes = [
'name' => 'Character',
'description' => 'Character interface.',
];
public function fields() {
return [
'id' => [
'type' => Type::nonNull(Type::int()),
'description' => 'The id of the character.'
],
'appearsIn' => [
'type' => Type::nonNull(Type::listOf(GraphQL::type('Episode'))),
'description' => 'A list of episodes in which the character has an appearance.'
],
];
}
public function resolveType($root) {
// Use the resolveType to resolve the Type which is implemented trough this interface
$type = $root['type'];
if ($type === 'human') {
return GraphQL::type('Human');
} else if ($type === 'droid') {
return GraphQL::type('Droid');
}
}
}
类型实现
<?php
// app/GraphQL/Types/HumanType.php
namespace App\GraphQL\Types;
use GraphQL;
use Folklore\GraphQL\Support\Type as GraphQLType;
use GraphQL\Type\Definition\Type;
class HumanType extends GraphQLType {
protected $attributes = [
'name' => 'Human',
'description' => 'A human.'
];
public function fields() {
return [
'id' => [
'type' => Type::nonNull(Type::int()),
'description' => 'The id of the human.',
],
'appearsIn' => [
'type' => Type::nonNull(Type::listOf(GraphQL::type('Episode'))),
'description' => 'A list of episodes in which the human has an appearance.'
],
'totalCredits' => [
'type' => Type::nonNull(Type::int()),
'description' => 'The total amount of credits this human owns.'
]
];
}
public function interfaces() {
return [
GraphQL::type('Character')
];
}
}
自定义字段
你同样可以定义一个字段类, 如果你想在多个类型中重用他们.
namespace App\GraphQL\Fields;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Field;
class PictureField extends Field {
protected $attributes = [
'description' => 'A picture'
];
public function type(){
return Type::string();
}
public function args()
{
return [
'width' => [
'type' => Type::int(),
'description' => 'The width of the picture'
],
'height' => [
'type' => Type::int(),
'description' => 'The height of the picture'
]
];
}
protected function resolve($root, $args)
{
$width = isset($args['width']) ? $args['width']:100;
$height = isset($args['height']) ? $args['height']:100;
return 'http://placehold.it/'.$width.'x'.$height;
}
}
你可以在 type 声明中使用他们
namespace App\GraphQL\Type;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as GraphQLType;
use App\GraphQL\Fields\PictureField;
class UserType extends GraphQLType {
protected $attributes = [
'name' => 'User',
'description' => 'A user'
];
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the user'
],
'email' => [
'type' => Type::string(),
'description' => 'The email of user'
],
//Instead of passing an array, you pass a class path to your custom field
'picture' => PictureField::class
];
}
}
加载关联关系
传递给 query 的 resolve 方法的第三个参数是 GraphQL\Type\Definition\ResolveInfo
的实例, 允许你从请求中取回指定的 key. 下面是一个使用这个参数的例子来获取关联模型的数据. 如下
namespace App\GraphQL\Query;
use GraphQL;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ResolveInfo;
use Folklore\GraphQL\Support\Query;
use App\User;
class UsersQuery extends Query
{
protected $attributes = [
'name' => 'Users query'
];
public function type()
{
return Type::listOf(GraphQL::type('user'));
}
public function args()
{
return [
'id' => ['name' => 'id', 'type' => Type::string()],
'email' => ['name' => 'email', 'type' => Type::string()]
];
}
public function resolve($root, $args, $context, ResolveInfo $info)
{
$fields = $info->getFieldSelection($depth = 3);
$users = User::query();
foreach ($fields as $field => $keys) {
if ($field === 'profile') {
$users->with('profile');
}
if ($field === 'posts') {
$users->with('posts');
}
}
return $users->get();
}
}
你的 UserType 可能看起来是这个样子的
<?php
namespace App\GraphQL\Type;
use Folklore\GraphQL\Support\Facades\GraphQL;
use GraphQL\Type\Definition\Type;
use Folklore\GraphQL\Support\Type as GraphQLType;
class UserType extends GraphQLType
{
/**
* @var array
*/
protected $attributes = [
'name' => 'User',
'description' => 'A user',
];
/**
* @return array
*/
public function fields()
{
return [
'uuid' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The uuid of the user'
],
'email' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The email of user'
],
'profile' => [
'type' => GraphQL::type('Profile'),
'description' => 'The user profile',
],
'posts' => [
'type' => Type::listOf(GraphQL::type('Post')),
'description' => 'The user posts',
]
];
}
}
这样我们有一个 profile 和一个 post 类型作为期待的返回关联关系数据
class ProfileType extends GraphQLType
{
protected $attributes = [
'name' => 'Profile',
'description' => 'A user profile',
];
public function fields()
{
return [
'name' => [
'type' => Type::string(),
'description' => 'The name of user'
]
];
}
}
class PostType extends GraphQLType
{
protected $attributes = [
'name' => 'Post',
'description' => 'A post',
];
public function fields()
{
return [
'title' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The title of the post'
],
'body' => [
'type' => Type::string(),
'description' => 'The body the post'
]
];
}
}
最后你的查询可能是这个样子, 使用 URL
http://homestead.app/graphql?query=query+FetchUsers{users{uuid, email, team{name}}}