ysll233/graphql-laravel5

Laravel5 对 PHP GraphQL 的包装

安装: 30

依赖者: 0

建议者: 0

安全: 0

星标: 0

关注者: 1

分支: 266

类型:项目

v1.15.8 2018-11-12 08:20 UTC

README

Latest Stable Version License

使用 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...
    }
}

高级用法