gregorip02/restql

Laravel 数据解析包

v2.9.2 2021-04-18 00:43 UTC

README

License Latest Stable Version Total Downloads Actions Status

RestQL 是一个基于 Laravel Eloquent 的数据解析包。这个包试图采用 GraphQL 原则,仅解决客户端请求的数据。RestQL 使用您的 Laravel 模型作为入口点,添加基于 Eloquent 方法的查询。

请参阅文档

Laravel RestQL

为什么?

想象一下,您有一个管理作者的应用程序,这些作者可以发布文章,这些文章可以有来自不同作者的评论。您有一个客户端,例如,使用 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 的查询。

优点

所以,假设现在您有一个需求告诉您需要每个作者最近发布的两篇文章的 idtitle

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,我将很高兴对其进行审查并添加。因此,您也可以通过购买一杯咖啡来为团队做出贡献。

Buy Us A Coffee