原文地址:
使用
语法 / 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 schemahttp://homestead.app/graphql?query=query+FetchUsers{users{id,email}}// Secret schemahttp://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 的扩展类型
'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 ];
然后如下使用
[ 'type' => GraphQL::type('TestEnum') ] ] }}
接口
你可以使用接口来限制一系列的字段, 阅读更多的消息点击
一系列的接口
'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'); } }}
类型实现
'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 可能看起来是这个样子的
'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}}}