dmavrin/graphql-laravel

Laravel的PHP GraphQL包装器

安装次数: 149

依赖者: 0

建议者: 0

安全性: 0

星标: 0

关注者: 0

分支: 266

类型:项目

6.0.0-rc2 2020-11-16 07:48 UTC

README

Latest Stable Version Build Status Style CI License Get on Slack

使用Facebook GraphQL与Laravel 5.5+。它基于此处的PHP实现here。您可以在GraphQL Introduction上找到有关GraphQL的更多信息,该文章发布在React博客,或者您也可以阅读GraphQL specifications。这是一个正在进行中的项目。

此软件包与Eloquent模型或任何其他数据源兼容。

  • 允许创建作为请求端点的查询突变
  • 可以为每个查询/突变定义自定义的中间件
  • 查询返回具有自定义隐私设置的类型
  • 可以通过使用SelectFields类从数据库中动态检索查询字段。

它提供了以下功能和改进,这些功能和改进优于Folklore的原始包

  • 按操作授权
  • 按字段回调定义其可见性(例如,从未认证用户中隐藏)
  • resolve()中可用SelectFields抽象,允许进行高级预加载,从而解决n+1问题
  • 支持分页
  • 支持服务器端查询批处理

安装

依赖项

安装

- 使用Composer安装包

composer require rebing/graphql-laravel
Laravel 5.5+

1. Laravel 5.5+将自动发现该软件包,对于旧版本,请将以下服务提供程序添加到您的config/app.php文件中。

Rebing\GraphQL\GraphQLServiceProvider::class,

和别名

'GraphQL' => 'Rebing\GraphQL\Support\Facades\GraphQL',

在您的config/app.php文件中。

2. 发布配置文件

$ php artisan vendor:publish --provider="Rebing\GraphQL\GraphQLServiceProvider"

3. 检查配置文件

config/graphql.php
Lumen(实验性!)

1. 将以下服务提供程序添加到bootstrap/app.php文件中

$app->register(Rebing\GraphQL\GraphQLLumenServiceProvider::class);

2. 发布配置文件

$ php artisan graphql:publish

3. 将配置添加到bootstrap/app.php文件中 重要: 这需要在注册服务提供程序之前完成

$app->configure('graphql');
...
$app->register(Rebing\GraphQL\GraphQLLumenServiceProvider::class);

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外观在服务提供程序中添加类型。

GraphQL::addType(\App\GraphQL\Type\UserType::class, 'user');

然后您需要定义一个查询,该查询返回此类型(或列表)。您还可以指定在 resolve 方法中可以使用的参数。

<?php

namespace App\GraphQL\Query;

use App\User;
use Rebing\GraphQL\Support\Facades\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
        ],
        // ...
    ]
]

就是这样。您应该能够通过向网址 /graphql(或您在配置中选择的任何网址)发出请求来查询 GraphQL。尝试以下 query 输入的 GET 请求

query FetchUsers {
    users {
        id
        email
    }
}

例如,如果您使用 homestead

http://homestead.app/graphql?query=query+FetchUsers{users{id,email}}

创建突变

变异类似于任何其他查询。它接受参数(这些参数将用于执行变异)并返回特定类型的对象。

例如,更新用户密码的变异。首先您需要定义变异

<?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() 方法中所示,您使用参数来更新您的模型并返回它。

然后您需要将变异添加到配置文件 config/graphql.php

'schemas' => [
    'default' => [
        'mutation' => [
            'updateUserPassword' => App\GraphQL\Mutation\UpdateUserPasswordMutation::class
        ],
        // ...
    ]
]

然后您应该能够在端点使用以下查询来执行变异

mutation users {
    updateUserPassword(id: "1", password: "newpassword") {
        id
        email
    }
}

如果您使用 homestead

http://homestead.app/graphql?query=mutation+users{updateUserPassword(id: "1", password: "newpassword"){id,email}}

给变异添加验证

可以向变异添加验证规则。它使用 Laravel 的 Validator 来对 $args 执行验证。

在创建变异时,您可以添加一个方法来定义应用的验证规则,方法如下

<?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']
            ]
        ];
    }

    //...

}

当您执行变异时,它将返回发生的任何验证错误。由于 GraphQL 规范定义了错误的一定格式,因此验证错误被添加到错误对象中的额外 validation 属性。要找到验证错误,您应该检查具有 message 等于 'validation' 的错误,然后 validation 属性将包含 Laravel Validator 返回的正常错误消息

{
    "data": {
        "updateUserEmail": null
    },
    "errors": [
        {
            "message": "validation",
            "locations": [
                {
                    "line": 1,
                    "column": 20
                }
            ],
            "validation": {
                "email": [
                    "The email is invalid."
                ]
            }
        }
    ]
}

返回的验证错误可以通过覆盖变异上的 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' => UploadType::getInstance(),
                'rules' => ['required', 'image', 'max:1500'],
            ],
        ];
    }

    public function resolve($root, $args)
    {
        $file = $args['profilePicture'];

        // Do something with file here...
    }
}

注意:您可以使用 Altair 来测试您的文件上传实现,具体说明请参阅 此处

高级用法