glesys / butler-graphql
针对Laravel的具有观点的GraphQL包
Requires
- php: ^8.2
- amphp/amp: ^2.5
- illuminate/support: ^11.0
- webonyx/graphql-php: ^14.3.0
Requires (Dev)
- graham-campbell/testbench: ^6.0
- laravel/pint: ^1.14
- mockery/mockery: ^1.4.4
- phpunit/phpunit: ^10.0
Suggests
- barryvdh/laravel-debugbar: View debug information in responses.
- dev-master
- dev-main
- v11.0.0
- v10.1.1
- v10.1.0
- v10.0.0
- v9.0.0
- v8.1.0
- v8.0.1
- v8.0.0
- v7.1.0
- v7.0.0
- v6.0.0
- v5.1.0
- v5.0.0
- v4.0.0
- v3.4.0
- v3.3.0
- v3.2.0
- v3.1.0
- v3.0.0
- v2.2.0
- v2.1.0
- v2.0.1
- v2.0.0
- v1.2.1
- v1.2.0
- v1.1.2
- v1.1.1
- v1.1.0
- v1.0.0
- v0.2.0
- v0.1.0
- dev-dependabot/composer/webonyx/graphql-php-tw-14.3.0or-tw-15.0.0
- dev-laravel-pint
- dev-support-resolvers-for-enums
- dev-mb-phpunit-config
- dev-dataloader-improvements
- dev-upgrade-webonyx-graphql
- dev-emil-nasso-patch-1
This package is auto-updated.
Last update: 2024-09-27 06:04:25 UTC
README
Butler GraphQL
Butler GraphQL是一个具有观点的包,它使得使用Laravel快速且轻松地提供GraphQL API变得简单。
入门
- 安装
glesys/butler-graphql
包。
composer require glesys/butler-graphql
注意:如果您使用的是Laravel < 5.5或Lumen,您需要手动注册Butler\Graphql\ServiceProvider::class
。
- 创建一个GraphQL模式文件。默认位置是
app/Http/Graphql/schema.graphql
。
type Query { pendingSignups: [Signup!]! } type Signup { email: String! verificationToken: String! }
- 为
pendingSignups
查询创建一个解析器。
<?php namespace App\Http\Graphql\Queries; class PendingSignups { public function __invoke($root, $args, $context) { return Signups::where('status', 'pending')->get(); } }
- 创建一个具有
Butler\Graphql\Concerns\HandlesGraphqlRequests
特质的主控制器。
<?php namespace App\Http\Controllers; use Butler\Graphql\Concerns\HandlesGraphqlRequests; class GraphqlController extends Controller { use HandlesGraphqlRequests; }
- 为您的GraphQL API端点添加路由。
$router->post('/graphql', GraphqlController::class);
深入了解
查询
查询解析器由位于App\Http\Graphql\Queries
命名空间中的类表示。它们应该与查询同名,但使用StudlyCased,即pendingSignups
=> PendingSignups
。
查询作为可调用项触发,因此您只需实现__invoke
方法即可。
所有解析方法都会传入以下参数
/** * @param mixed $root * @param array $args * @param array $context * @param \GraphQL\Type\Definition\ResolveInfo $info */
除了从解析方法返回可数组和对象之外,您还可以返回可调用项,这些可调用项将以相同的参数集调用。
public function __invoke() { return function ($root, $args, $context, $info) { // }; }
突变
突变解析器由位于App\Http\Graphql\Mutations
命名空间中的简单类表示。
从技术上讲,突变和查询是同一件事。它们都可以接受参数并返回带有字段的数据类型。将它们分开更多的是一种约定,而不是一种要求。
在REST中,任何请求都可能对服务器产生一些副作用,但按照约定,不建议使用GET请求来修改数据。GraphQL类似,从技术上讲,任何查询都可以实现为导致数据写入。然而,建立一个约定,即任何导致写入的操作应显式通过突变发送,是有用的。
类型
解析类型字段与查询和突变一样简单。在App\Http\Graphql\Types
命名空间中定义一个简单的类,并为字段使用camelCased方法名称。
<?php namespace App\Http\Graphql\Types; class Signup { public function verificationToken($source, $args, $context, $info) { return $source->token; } }
注意:如果您在GraphQL模式定义中的字段名称与源对象的键(对于可数组)或属性(对于对象)匹配,则不需要为该字段定义解析器方法。
接口
Butler GraphQL支持在模式中使用接口,但需要一点帮助才能知道用于解析字段的数据类型。
告诉Butler GraphQL使用什么类型的最容易的方法是提供数据中的__typename
键或属性。例如
<?php namespace App\Http\Graphql\Types; class Post { public function attachment($source, $args, $context, $info) { return [ '__typename' => 'Photo', 'height' => 200, 'width' => 300, ]; } }
您还可以在父解析器中使用resolveTypeFor[Field]
来动态决定使用哪种类型
<?php namespace App\Http\Graphql\Types; class Post { public function attachment($source, $args, $context, $info) { return [ 'height' => 200, 'width' => 300, ]; } public function resolveTypeForAttachment($source, $context, $info) { if (isset($source['height'], $source['width'])) { return 'Photo'; } if (isset($source['length'])) { return 'Video'; } } }
对于查询和突变,您只需定义一个resolveType
方法
<?php namespace App\Http\Graphql\Queries; use App\Attachment; class Attachments { public function __invoke($source, $args, $context, $info) { return Attachment::all(); } public function resolveType($source, $context, $info) { return $source->type; // `Photo` or `Video` } }
如果没有上述任何一种,且数据是对象,Butler GraphQL将回退到数据的基本类名。
N+1和数据加载器
Butler GraphQL包括一个简单的数据加载器,以防止在加载嵌套数据时出现n+1问题。它在$context['loader']
中可用,并且非常易于使用
<?php namespace App\Http\Graphql\Types; use App\Models\Article; class Article { public function comments(Article $source, $args, $context, $info) { return $context['loader'](function ($articleIds) { return Comment::whereIn('article_id', $articleIds) ->cursor() ->groupBy('article_id'); }, [])->load($source->id); } }
注意: 您可以将默认值作为加载器工厂的第二个参数提供。当您知道某些文章可能没有评论时,这很有用,例如上面的示例中。默认值为 null
。
共享数据加载器
如果您有多个解析器与相同的基本数据一起工作,您不需要复制代码或处理数据库的额外往返。
您需要做的就是定义一个单独的加载器函数,并在解析器中重用它。
<?php namespace App\Http\Graphql\Types; use App\Models\Article; use Closure; class Article { public function comments(Article $source, $args, $context, $info) { return $context['loader'](Closure::fromCallable([$this, 'loadComments']), []) ->load($source->id); } public function topVotedComment(Article $source, $args, $context, $info) { $comments = yield $context['loader'](Closure::fromCallable([$this, 'loadComments'])) ->load($source->id); return collect($comments)->sortByDesc('votes')->first(); } private function loadComments($articleIds) { return Comment::whereIn('article_id', $articleIds) ->cursor() ->groupBy('article_id'); } }
Butler GraphQL 将确保 loadComments
只调用一次。
如果您不想使用 Closure::fromCallable(...)
,您可以将 loadComments
的可访问性更改为 public
。
将大型模式文件拆分为多个文件
Butler GraphQL 允许您轻松地将 GraphQL 模式文件的某些部分拆分到单独的文件中。
schema.graphql
type Query { users: [User!]! } type User { id: ID! username: String! }
schema-user-attributes.graphql
extend type User { firstName: String lastName: String email: String! }
注意: 基础模式总是必需的,并且建议避免使用多级扩展。
自定义
实际上没有真正需要配置 Butler GraphQL。它考虑到 约定优于配置,应该可以在没有任何配置的情况下立即使用。
如果您想覆盖任何可用设置,可以使用以下环境变量之一发布配置文件。
php artisan vendor:publish
更改模式位置和命名空间
BUTLER_GRAPHQL_SCHEMA
– 默认为app_path('Http/Graphql/schema.graphql')
。BUTLER_GRAPHQL_NAMESPACE
– 默认为'App\\Http\\Graphql\\'
。
更改部分模式文件的路径和模式
BUTLER_GRAPHQL_SCHEMA_EXTENSIONS_PATH
– 默认为app_path('Http/Graphql/')
。BUTLER_GRAPHQL_SCHEMA_EXTENSIONS_GLOB
– 默认为'schema-*.graphql'
。
调试
BUTLER_GRAPHQL_INCLUDE_DEBUG_MESSAGE
– 设置为true
以在错误响应中包含实际的错误消息。默认为false
。BUTLER_GRAPHQL_INCLUDE_TRACE
– 设置为true
以在错误响应中包含堆栈跟踪。默认为false
。
Debugbar
Butler GraphQL 支持在使用 laravel-debugbar 时自动装饰响应,以包含额外的调试信息。如果已安装 barryvdh/laravel-debugbar,则数据库查询和内存使用等详细信息将自动在响应中可用。
要安装和激活它,只需将 barryvdh/laravel-debugbar
作为 require-dev
依赖项安装即可。
composer require barryvdh/laravel-debugbar --dev
安装后,请确保 APP_DEBUG
设置为 true
,就这么简单。
通过将默认配置文件 default config file 复制到 config/debugbar.php
并根据需要进行调整,可以轻松地自定义要收集并包含在响应中的数据。
授权
如果您需要授权 GraphQL 请求,您可以使用 beforeExecutionHook
方法来检查模式和查询,并在那里实现您的授权逻辑。
<?php namespace App\Http\Controllers; use Butler\Graphql\Concerns\HandlesGraphqlRequests; use GraphQL\Type\Schema; use GraphQL\Language\AST\DocumentNode; class GraphqlController extends Controller { use HandlesGraphqlRequests; /** * @param $schema A parsed version of your GraphQL schema * @param $query A parsed version of the consumer's query * @param $operationName The passed operation name (for when the query contains multiple operations) * @param $variables Any variables passed alongside the query */ public function beforeExecutionHook(Schema $schema, DocumentNode $query, string $operationName = null, $variables = null): void { // TODO: Implement custom authorization logic here } }
如何贡献
开发发生在 GitHub 上;任何使用拉取请求的典型工作流程都受到欢迎。同样,我们使用 GitHub 问题跟踪器来处理所有报告(无论报告的性质如何,功能请求、错误等)。
所有更改都应覆盖单元测试,如果测试不可能或非常不实际,那么在拉取请求的评论部分进行讨论是有道理的。
代码标准
由于库旨在用于 Laravel 应用程序,我们鼓励遵循 上游 Laravel 实践 的代码标准 - 简而言之,这意味着 PSR-2 和 PSR-4。