gregorip02 / restql
Laravel 数据解析包
Requires
- php: ^7.1|^8.0
- laravel/framework: ^5.8|^6.2|^7.3|^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.18
- orchestra/testbench: ^3.7|^4|^5|^6
- phpunit/phpunit: ^7.5|^8
README
RestQL 是一个基于 Laravel Eloquent 的数据解析包。这个包试图采用 GraphQL 原则,仅解决客户端请求的数据。RestQL 使用您的 Laravel 模型作为入口点,添加基于 Eloquent 方法的查询。
请参阅文档。
为什么?
想象一下,您有一个管理作者的应用程序,这些作者可以发布文章,这些文章可以有来自不同作者的评论。您有一个客户端,例如,使用 fetch 消费您服务提供的数据,并在您的代码中需要作者名称列表的地方。
这看起来像这样。
fetch('https://laravel.app/api/authors') .then((res) => res.json()) .then(({ data }) => console.log(data.authors));
因此,您有一个这样的路由。
routes/api.php
<?php use App\Author; use Illuminate\Http\Request; Route::get('/authors', function (Request $request) { $authors = Author::take(25)->get(); return ['data' => compact('authors')]; });
很可能会使用控制器,然后使用作者模型查询数据。最后,您将得到一个类似的响应。
{ "data": { "authors": [ { "id": 1, "name": "Lazaro Kohler", "email": "greenfelder.jenifer@example.org", "email_verified_at": "2020-03-19T18:11:36.000000Z", "created_at": "2020-03-19T18:11:36.000000Z", "updated_at": "2020-03-19T18:11:36.000000Z" }, { "id": 2, "name": "Miss Anastasia Klocko DVM", "email": "lemke.trinity@example.org", "email_verified_at": "2020-03-19T18:11:36.000000Z", "created_at": "2020-03-19T18:11:36.000000Z", "updated_at": "2020-03-19T18:11:36.000000Z" }, { /* 23 more authors */ } ] } }
但是,如果您只需要一个例如 作者名称 集合呢?想象一下,您的应用程序变得很大,用户模型处理大量属性。
开始使用
使用 composer 安装 RestQL。
composer require gregorip02/restql
发布包配置。
php artisan restql:schema
将 RestqlAttributes
特性添加到您的 Eloquent 模型中。
2.2 这是因为您可以使用
onSelectFillable
确定可选择的属性。
<?php use Illuminate\Database\Eloquent\Model; use Restql\Traits\RestqlAttributes; class Author extends Model { use RestqlAttributes; // ... }
为您的 App\Models\Author
模型生成一个 authorizer
。
php artisan restql:authorizer AuthorAuthorizer
这将在命名空间 App\Restql\Authorizers\AuthorAuthorizer
中创建一个新类,如下所示。
<?php namespace App\Restql\Authorizers; use Restql\Authorizer; final class AuthorAuthorizer extends Authorizer { // ... }
然后,按照以下方式添加您的授权器中可用的 HTTP 方法。
<?php namespace App\Restql\Authorizers; use Restql\Authorizer; final class AuthorAuthorizer extends Authorizer { /** * Can get one or more author resources. * * @param array $clausules * @return bool */ public static function get(array $clausules = []): bool { // You could replace this with permission checks or validations. return true; } }
然后,设置您的模式定义。
自本包的 2.x 版本以来,配置已更新以提高灵活性和内部行为修改。
您必须在配置文件中定义您的整个模式,RestQL 将根据此文件解释并执行查询。这样,您就可以删除内部函数、修改它们,甚至创建自己的实现。请参阅模式定义。
config/restql.php
<?php use App\Models\Author; use App\Restql\Authorizers\AuthorAuthorizer; return [ // ... 'schema' => [ 'authors' => [ 'class' => Author::class, 'authorizer' => AuthorAuthorizer::class, 'middlewares' => [] ] ], // ... ];
开发人员必须指定 Eloquent 模型中定义的关联的返回类型。您应该设置关联方法的返回类型(关系)。例如。
app/Models/Author.php
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; class Author extends Model { /** * Get the author articles. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function articles(): {} // Bad public function articles(): HasMany {} // Good }
配置您的端点。
routes/api.php
<?php use Restql\Restql; use Illuminate\Http\Request; Route::get('/restql', fn (Request $request) => Restql::resolve($request));
重构时间
现在,您可以将客户端代码重构,使其发送一个参数到请求中,其中包含它需要的数据,在这种情况下是一个作者名称的集合。这看起来像这样。
const { stringify } = require('qs'); // Define your queries. const getAuthorsQuery = { authors: { select: ['name'] } }; // Consume the restql endpoint. fetch(`https://laravel.app/restql?${stringify(getAuthorsQuery)}`) .then((res) => res.json()) .then((res) => console.log(res));
查询的参数应该是解析后的对象,该对象定义了您的模式定义中接受的子句。对于您的 Web 客户端,我们推荐使用 qs。 而不是得到一个包含不必要数据的冗长 JSON 响应,您将得到类似这样的结果。
{ "data": { "authors": [ { "id": 1, "name": "Kasey Yost" }, { "id": 2, "name": "Ike Barton" }, { "id": 3, "name": "Emie Daniel" }, { /* 22 more authors */ } ] } }
同样,这将大大优化您的数据库查询。在这种情况下,它将运行一个类似 select id, name from authors
的查询。
优点
所以,假设现在您有一个需求告诉您需要每个作者最近发布的两篇文章的 id
和 title
。
const { stringify } = require('qs'); // Define your queries. const getAuthorsAndTwoLatestArticlesQuery = { authors: { select: ['name'], with: { articles: { take: 2 select: 'title', sort: { column: 'published_at', direction: 'desc' }, } } } }; // Consume the restql endpoint. fetch(`https://laravel.app/restql?${stringify(getAuthorsAndTwoLatestArticlesQuery)}`) .then((res) => res.json()) .then((res) => console.log(res));
您将得到这样一个响应。
{ "data": { "authors": [ { "id": 1, "name": "Kasey Yost", "articles": [ { "id": 3434, "title": "My awesome article" } ] }, { /* 24 more authors */ } ] } }
它是如何工作的
基本上,RestQL会过滤HTTP请求中接收到的模型的键,并将它们与用户配置的键进行比较。这些键代表一个特定的Eloquent模型。这些键的值是RestQL接受的Eloquent子句(方法),而这些子句的参数作为值发送。
例如,如果请求中发送了以下类似的params。
{ "authors": { "select": "name", "with": { "articles": { "select": "title" } } } }
RestQL会将其解释为以下内容。
<?php // Assuming that the parent model we want to obtain is the author's data. // The variable $query represents the query constructor of the parent model, // in this example, the Author model. $query->select(['name'])->with([ 'articles' => static function (Relation $relation) { $relation->select(['title']); } ]);
您可以在这里了解更多关于RestQL子句的信息。
接下来是什么?
您是否想为此项目做出贡献?请查看NEXT.md文件。
贡献
感谢您考虑为此项目做出贡献,请参阅此页面的开发文档。
请支持它
这是一个非常有用的个人项目,如果您相信它,请帮助我开发新的功能并创建一个pull request,我将很高兴对其进行审查并添加。因此,您也可以通过购买一杯咖啡来为团队做出贡献。