使用 PHP8 特性的 Laravel 的 graphql-php 包装器

0.0.3 2021-04-18 23:52 UTC

This package is auto-updated.

Last update: 2024-09-19 07:22:42 UTC


README

[WIP] 一个优雅的 webonyx/graphql-php 包装器,使用 PHP 8 特性。

安装

要求:PHP 8

composer require scriptle/laragraph

使用

发布配置文件

php artisan vendor:publish --provider=Scriptle\\Laragraph\\LaragraphServiceProvider

根据您的喜好修改模式。

文件夹结构

  • 突变根位于 app/GraphQL/Mutations
  • 查询根位于 app/GraphQL/Queries
  • 类型位于 app/GraphQL/Types

app/Models 也会遍历具有 GraphQL 类型 属性的模型。

模式

模式定义在 config/laragraph.php 中的 schemas 键下。

return [
    'prefix' => 'gql',
    'schemas' => [
        'v1' => [
            'schema' => [
                'query' => 'V1Query',
                'mutation' => 'V1Mutation',
            ],
            'middleware' => null,
        ],
        /* 'v2' => [
        *       'schema' => [
        *           'query' => 'V2Query',
        *           'mutation' => 'V2Mutation',
        *       ],
        *       'middleware' => 'throttle:60,1',
        *   ]
        */
    ]
];

前缀(gql)将添加到所有模式。模式键是 URL。因此,对于 v1,完整 URL 是 /gql/v1

schema 键中,您像平常一样定义您的 GraphQL 模式,通过字符串引用根类型。

您可以使用该键添加自定义 中间件,例如仅限于管理员用户的完整模式。

然后,您必须添加您定义的根类型,如下所示

namespace App\GraphQL\Queries;
use Scriptle\Laragraph\Type;
use App\Models\User;
...
#[Type('V1Query', 'Root queries for v1')]
class V1Query {
    #[Field('users', '[User]!', 'Lists all users.')]
    public function users() {
        return User::all();
    }
    
    // More on this later
    #[Field('lookupUser("User ID" id: String, "User Email" email: String)', 'User', 'Look up a user by ID or email.')]
    public function lookupUser($args) {
        // More on this later
        return User::where($args)->first();
    }
}

属性

上,添加以下属性

namespace App\Models\User;
use Scriptle\Laragraph\Type;
...
#[Type]
class User extends Authenticatable {
    ...
}

#[Type] 单独使用将使用类名作为 GraphQL 类型名。

#[Type('Person')] 将使用 Person 作为 GraphQL 类型名。

#[Type('User', '数据库中的用户。')] will use User as the GraphQL type name, plus a GraphQL introspection descriptor for this type.

定义字段

要定义通过 Eloquent 返回的简单字段,您可以使用带有 Type 属性的方式简单地将它们附加

namespace App\Models\User;
use Scriptle\Laragraph\Type;
use Scriptle\Laragraph\Field;
...
#[
    Type('User', 'A user in the database.'),
    Field('id', 'String!', 'User ID'),
    Field('first_name', 'String!', "User's first name"),
    Field('last_name', 'String!', "User's last name"),
    Field('roles', '[Role]!', 'Array of user roles'),
]
class User extends Authenticatable {
    ...
}

注意:以这种方式自动支持 Eloquent 关系。

具有自定义解析器的字段

如果您的字段不是基于数据库的,或需要通过回调传递,则可以使用此功能。

OR

namespace App\Models\User;
use Scriptle\Laragraph\Type;
use Scriptle\Laragraph\Field;
...
#[
    Type('User', 'A user in the database.'),
    Field('id', 'String!', 'User ID'),
    Field('first_name', 'String!', "User's first name"),
    Field('last_name', 'String!', "User's last name"),
    Field('roles', '[Role]!', 'Array of user roles'),
]
class User extends Authenticatable {
    ...
    public function resolveLastNameField()
    {
        return strtoupper($this->attributes['last_name']);
    }
}

格式:resolve + (StudlyCase) LastName + Field = resolveLastNameField

OR

namespace App\Models\User;
use Scriptle\Laragraph\Type;
use Scriptle\Laragraph\Field;
use Scriptle\Laragraph\ResolvesFor;
...
#[
    Type('User', 'A user in the database.'),
    Field('id', 'String!', 'User ID'),
    Field('first_name', 'String!', "User's first name"),
    Field('last_name', 'String!', "User's last name"),
    Field('roles', '[Role]!', 'Array of user roles'),
]
class User extends Authenticatable {
    ...
    #[ResolvesFor('last_name')]
    public function getLastNameAttribute()
    {
        return strtoupper($this->attributes['last_name']);
    }
}

函数可以命名为任何名称,只要它具有 ResolvesFor 属性。这很好地与 Laravel 的自定义获取器集成。

OR 最后

namespace App\Models\User;
use Scriptle\Laragraph\Type;
use Scriptle\Laragraph\Field;
...
#[
    Type('User', 'A user in the database.'),
    Field('id', 'String!', 'User ID'),
    Field('first_name', 'String!', "User's first name"),
    Field('roles', '[Role]!', 'Array of user roles'),
]
class User extends Authenticatable {
    ...
    #[Field('last_name', 'String!', "User's last name")]
    public function anything()
    {
        return strtoupper($this->attributes['last_name']);
    }
}

如果喜欢这种风格,可以将字段属性移到函数中。

有参数的字段

某些字段,特别是在查询中,需要参数。语法是直接的 GraphQL 定义语法

#[Field('lookupUser("User ID" id: String!)', 'User', '通过 ID 查找一个用户。')] defines a lookupUser field with 1 argument, id of type String! (with ! so it must be non-null) and with introspection description of User ID.

这定义了一个 lookupUser 字段,具有 1 个参数,id 类型为 String!(由于 !,它必须是非空的)和 User ID 的内省描述。

可以为突变或查询类型上的字段做同样的事情。

自定义类型

可以像上面的 User 模型一样定义自定义类型,并将它们放在 app/GraphQL/Types 文件夹中以保持与模型分离。这对于突变响应或其他复杂响应结构很有用。

类型通过其类型名称(由 #[Type] 属性注册)引用,就像常规 GraphQL 一样。不需要创建变量或直接引用类!

缓存

config/laragraph.php 将与 Laravel 的常规配置缓存(php artisan config:cachephp artisan config:clear)一起缓存。

您还可以缓存Laragraph的类型映射,以避免在每次请求中处理它们。使用php artisan gql:cache进行缓存,并使用php artisan gql:clear进行清除。