nolka/yii2-api-manager

Yii2 的 REST API 字段管理和 Swagger 生成扩展

安装次数: 1,367

依赖者: 0

建议者: 0

安全: 0

星标: 1

关注者: 3

分支: 1

开放问题: 1

类型:yii2-extension

dev-master 2021-02-07 15:54 UTC

This package is auto-updated.

Last update: 2024-09-07 23:05:59 UTC


README

这是一款用于构建具有灵活数据过滤设置和自动生成程序接口文档的 API 扩展。

组件使用

假设 API 是基于 Yii2 框架的项目中独立的应用程序,并位于名为 api 的单独目录中。要使用此组件,只需将其添加到应用程序 api 的组件配置部分。

    'fieldManager' => [
        'class' => \apiman\FieldManager::class,
        'enableRules' => true,
        'rules' => require(__DIR__ . '/fields.php'),
        'cache' => true,
    ],

此外,还需要在配置目录中创建一个名为 fields.php 的文件,用于指定数据过滤规则。示例内容:

<?php

use apiman\conditions\TypeRule;

return [
    [
        // Тип правила - объект. Используется для генерации документации и ответов API для AR моделей,
        // и дочерних классов ModelResponse. 
        'type' => TypeRule::TYPE_OBJECT,
        'className' => [
            \api\versions\v1\models\User::class,
        ],
        'rules' => [
            [
                 // Псевдоним для генератора документации. Используется для генерации различных моделей для различных маршрутов
                'classNameDoc' => 'UserOne', 
                'route' => [
                    // Список маршрутов, для которых будут отдаваться перечисленные ниже поля,
                    // и генерироваться документация.

                    // profile
                    'user/profile/index',
                    'user/profile/update',
                ],
                'fields' => [
                    // Список полей модели User, которые будут отдаваться в ответе на запрос
                    'id', 'first_name', 'last_name', 'email', 'registered_at'
                ],
                'expands' => [
                    // Список связей, которые можно развернуть в ответе на запрос
                    'posts',
                ],
            ],
        ],
    ],
];

假设 API 对任何请求都返回 DataProviderInterface,该接口已序列化为 json 或 xml,具体取决于请求的头部。

文档生成和显示

文档生成器解决的问题是一直保持文档的时效性。您无需编写大量 Swagger 注解,而是在数据模型中只需描述一个轻量级结构,其中包含字段名称、数据类型和文本描述,以便用户更容易理解文档。接下来,文档生成器就派上用场了。注意:对于 API 方法,Swagger 文档需要手动编写。

连接

为了显示 Swagger 文档,使用了扩展 zircote/swagger-php。要生成 Swagger 文档,需要在控制台应用程序的 modules 部分连接 apiman\Module 模块。

///...
'modules' => [
    'apiman' => [
        'class' => \apiman\Module::class,
    ],
],
///...

连接模块后,将提供两个命令:一个用于生成文档,另一个用于验证模型和 fields.php 中的规则中的填充数据的有效性。此外,还将检查 fields.php 中是否存在缺失的路由或已删除且不再有效的 API 方法。目前,文档在一个包含多个 PHP 类的文件中生成,基于该文件,扩展 zircote/swagger-php 生成用于在浏览器中显示的 json 对象。生成的文件位于 @api/runtime/fields/swagger.php

使用命令 yii apiman/doc/generate 生成文档,使用命令 yii apiman/doc/validate 验证文档。

在验证文档的过程中,也会像第一次那样生成文档,但此时不会将生成的数据写入文件。

示例

基于 fields.php 中的示例,我们将描述一个用户类,该类用于生成文档,以及一个控制器示例。

用户模型

<?php

namespace api\versions\v1\models;

/**
 * Class User
 * @package api\versions\v1\models
 */
class User extends \common\models\User
{
    /**
     * Список полей модели, отдающихся в API
     * @return array
     */
    public function fields(): array
    {
        return [
            'id',
            'first_name',
            'last_name',
            'email',
            'registered_at',
        ];
    }

    /**
     * Список связей, возможных для запроса в API
     * @return array
     */
    public function extraFields(): array
    {
        return [
            'posts',
        ];
    }

    /**
     * Структура данных, описывающая поля модели, на основе которых будет производиться генерация
     * @return array
     */
    public function attributeDetails(): array
    {
        return [
            'id:integer:ID',
            'fname:string:Имя',
            'mname:string:Отчество',
            'lname:string:Фамилия',
            'email:string:Почта',
            'image:string:Ссылка на аватарку',
        ];
    }

    /**
     * Структура данных, описывающая связи модели, которые можно запросить в API 
     * @return array
     */
    public function expandDetails(): array
    {
        return [
            'posts:Список постов пользователя',
        ];
    }

    /**
    * Посты пользователя
    * @return \yii\db\ActiveQuery
     */
    public function getPosts()
    {
        return $this->hasMany(Post::class, ['user_id' => 'id']);
    }
}

由于所有 API 方法都位于应用程序的单独模块中,我们将描述一个用于先前提到的模型的控制器。

<?php

namespace api\versions\v1\modules\user\controllers;

use apiman\base\RestController;
use api\versions\v1\models\User;
use Yii;

/**
 * Class UserController
 * @package api\versions\v1\modules\user\controllers
 */
class UserController extends RestController
{
    /**
     * Данные о пользователе
     * @return User|array
     *
     * @SWG\Get(path="/user/profile",
     *     tags={"User"},
     *     summary="Данные о пользователе",
     *     description="",
     *     produces={"application/json", "application/xml"},
     *     @SWG\Parameter(
     *        in="header",
     *        name="Authorization",
     *        description="Bearer your_token",
     *        default="Bearer ",
     *        type="string"
     *     ),
     *     @SWG\Parameter(
     *         in="query",
     *         name="fields",
     *         type="string",
     *         default="id,first_name,last_name,email,posts.id,posts.title",
     *         description="Список полей",
     *     ),
     *     @SWG\Parameter(
     *         in="query",
     *         name="expand",
     *         type="string",
     *         default="posts",
     *         description="Список связей",
     *     ),
     *     @SWG\Response(
     *         response="200",
     *         description="Success",
     *         @SWG\Schema(
     *             title="response",
     *             type="object",
     *             @SWG\Property(
     *                 property="data",
     *                 type="object",
     *                 ref="#/definitions/User_UserUserProfile"
     *             )
     *         )
     *     )
     * )
     *
     */
    public function actionProfile()
    {
        if (!Yii::$app->user->isGuest) {
            return User::findOne(Yii::$app->user->id);
        }
        throw new yii\web\ForbiddenHttpException(); 
    }
}

在上面的示例中,我们特别关注响应方案中的描述,其中包含 ref="#/definitions/User_UserUserProfile" 字符串。具体来说,是 User_UserUserProfile 部分。这正是生成器在调用文档生成器时将生成的模型名称。模型的名称按照以下模式生成:%ModelName%_%ModuleName%%ControllerName%%ActionName%,即,由于用户模型由 API 模块 user、控制器 UserController 和操作 actionProfile 返回,因此模型的名称将是 User_UserUserProfile

API 请求

默认情况下,FieldManager 对于任何 API 请求都不会返回任何数据。要使其返回数据,需要通过 api fields 和 expand 参数进行请求。这个机制与 Yii 的标准方法类似,但不同之处在于需要明确列出所需的数据。这样做是为了节省流量,因为可能用户不需要请求整个用户资料的完整数据集,只需要姓名就足够了。这时,用户需要按照以下方式列出这些字段:%host%/v1/user/profile?field=first_name,last_name