ysll233 / graphql-laravel5
Laravel5 对 PHP GraphQL 的包装
Requires
- php: >=5.5.9
- illuminate/support: 5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*
- laravel/framework: 5.1.*|5.2.*|5.3.*|5.4.*|5.5.*|5.6.*|5.7.*
- webonyx/graphql-php: ~0.12.6
Requires (Dev)
- orchestra/testbench: 3.1.*|3.2.*|3.3.*|3.4.*|3.5.*
- phpunit/phpunit: ^5.5|~6.0|~7.0
README
使用 Laravel 5 的 Facebook GraphQL。它基于以下 PHP 实现 这里。您可以在 GraphQL 简介(位于 React 博客)中找到更多关于 GraphQL 的信息,或者您可以阅读 GraphQL 规范。这是一个正在进行中的项目。
此包与 Eloquent 模型或任何其他数据源兼容。
- 允许创建作为请求端点的 查询 和 突变
- 可以为每个查询/突变定义自定义 中间件
- 查询返回 类型,可以具有自定义 隐私 设置。
- 查询的字段将可以选择使用
SelectFields
类从数据库中 动态 获取。
它提供了以下特性和对原始包(由 Folklore 提供)的改进:
- 按操作授权
- 按字段回调定义其可见性(例如,从未认证用户中隐藏)
- 在
resolve()
中提供SelectFields
抽象,允许进行高级预加载,从而处理 n+1 问题 - 支持分页
- 支持服务器端 查询批处理
安装
依赖关系
安装
1. 通过 Composer 需求此包
composer require rebing/graphql-laravel
2. Laravel 5.5+ 将自动发现此包,对于旧版本,请将以下服务提供程序
Rebing\GraphQL\GraphQLServiceProvider::class,
和别名
'GraphQL' => 'Rebing\GraphQL\Support\Facades\GraphQL',
添加到您的 config/app.php
文件中。
3. 发布配置文件
$ php artisan vendor:publish --provider="Rebing\GraphQL\GraphQLServiceProvider"
4. 查看配置文件
config/graphql.php
用法
高级用法
模式
模式是必需的,用于定义 GraphQL 端点。您可以定义多个模式并将不同的 中间件 分配给它们,此外还有全局中间件。例如
'schema' => 'default_schema', 'schemas' => [ 'default' => [ 'query' => [ 'example_query' => ExampleQuery::class, ], 'mutation' => [ 'example_mutation' => ExampleMutation::class, ], ], 'user' => [ 'query' => [ 'profile' => App\GraphQL\Query\ProfileQuery::class ], 'mutation' => [ ], 'middleware' => ['auth'], ], ],
创建查询
首先,您需要创建一个类型。如果指定关系,则需要 Eloquent 模型。
注意:如果是一个非数据库字段或不是关系,则需要
selectable
键
<?php namespace App\GraphQL\Type; use App\User; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Type as GraphQLType; class UserType extends GraphQLType { protected $attributes = [ 'name' => 'User', 'description' => 'A user', 'model' => User::class, ]; public function fields() { return [ 'id' => [ 'type' => Type::nonNull(Type::string()), 'description' => 'The id of the user', 'alias' => 'user_id', // Use 'alias', if the database column is different from the type name ], 'email' => [ 'type' => Type::string(), 'description' => 'The email of user', ], // Uses the 'getIsMeAttribute' function on our custom User model 'isMe' => [ 'type' => Type::boolean(), 'description' => 'True, if the queried user is the current user', 'selectable' => false, // Does not try to query this from the database ] ]; } // 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::class ]
您也可以通过服务提供程序等将类型添加到 GraphQL
Facade 中。
GraphQL::addType(\App\GraphQL\Type\UserType::class, 'user');
然后,您需要定义一个返回此类型(或列表)的查询。您还可以指定在 resolve 方法中使用的参数。
<?php namespace App\GraphQL\Query; use App\User; use GraphQL; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Query; 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) { if (isset($args['id'])) { return User::where('id' , $args['id'])->get(); } if (isset($args['email'])) { return User::where('email', $args['email'])->get(); } return User::all(); } }
将查询添加到 config/graphql.php
配置文件中
'schemas' => [ 'default' => [ 'query' => [ 'users' => App\GraphQL\Query\UsersQuery::class ], // ... ] ]
就是这样。你应该可以使用到url /graphql
(或你配置中选择的任何内容)的请求来查询GraphQL。尝试使用以下query
输入进行GET请求
query FetchUsers {
users {
id
email
}
}
例如,如果你使用homestead
http://homestead.app/graphql?query=query+FetchUsers{users{id,email}}
创建突变
一个mutation就像任何其他查询一样。它接受参数(这些参数将被用来执行mutation)并返回一个特定类型的对象。
例如,更新用户密码的mutation。首先你需要定义Mutation
<?php namespace App\GraphQL\Mutation; use App\User; use GraphQL; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Mutation; 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
配置文件中
'schemas' => [ 'default' => [ 'mutation' => [ 'updateUserPassword' => App\GraphQL\Mutation\UpdateUserPasswordMutation::class ], // ... ] ]
然后你应该可以在你的端点上使用以下查询来进行mutation
mutation users {
updateUserPassword(id: "1", password: "newpassword") {
id
email
}
}
如果你使用homestead
http://homestead.app/graphql?query=mutation+users{updateUserPassword(id: "1", password: "newpassword"){id,email}}
向mutation添加验证
向mutation添加验证规则是可能的。它使用Laravel的Validator
来对$args
执行验证。
在创建mutation时,你可以通过以下方式添加一个方法来定义应用的验证规则
<?php namespace App\GraphQL\Mutation; use App\User; use GraphQL; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\Mutation; 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(array $args = []) { 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'] ] ]; } //... }
当你执行mutation时,它将返回任何发生的验证错误。由于GraphQL规范定义了错误的一定格式,验证错误将被添加到错误对象中作为额外的validation
属性。为了找到验证错误,你应该检查具有message
等于'validation'
的错误,然后validation
属性将包含由Laravel Validator返回的正常错误消息
{ "data": { "updateUserEmail": null }, "errors": [ { "message": "validation", "locations": [ { "line": 1, "column": 20 } ], "validation": { "email": [ "The email is invalid." ] } } ] }
返回的验证错误可以通过覆盖mutation上的validationErrorMessages
方法来自定义。该方法应该返回一个与Laravel的验证文档中相同方式的自定义验证消息数组。例如,为了检查一个email
参数是否与任何现有数据冲突,你可以执行以下操作
注意:键应该使用
field_name
.validator_type
格式,这样你可以为每个验证类型返回特定的错误。
public function validationErrorMessages ($args = []) { return [ 'name.required' => 'Please enter your full name', 'name.string' => 'Your name must be a valid string', 'email.required' => 'Please enter your email address', 'email.email' => 'Please enter a valid email address', 'email.exists' => 'Sorry, this email address is already in use', ]; }
文件上传
仅使用UploadType
上传新文件。这种上传文件的支持基于https://github.com/jaydenseric/graphql-multipart-request-spec,所以你必须以多部分表单的形式上传它们
警告:当你上传文件时,Laravel将使用FormRequest - 这意味着更改请求的中间件将没有任何效果。
<?php use GraphQL; use GraphQL\Type\Definition\Type; use Rebing\GraphQL\Support\UploadType; use Rebing\GraphQL\Support\Mutation; class UserProfilePhotoMutation extends Mutation { protected $attributes = [ 'name' => 'UpdateUserProfilePhoto' ]; public function type() { return GraphQL::type('user'); } public function args() { return [ 'profilePicture' => [ 'name' => 'profilePicture', 'type' => new UploadType($this->attributes['name']), 'rules' => ['required', 'image', 'max:1500'], ], ]; } public function resolve($root, $args) { $file = $args['profilePicture']; // Do something with file here... } }