freimaurerei/yii2-json-rpc-2.0

为 Yii2 提供严格请求和响应数据类型验证的 JSON RPC 2.0

1.2.8.3 2017-06-08 15:16 UTC

This package is not auto-updated.

Last update: 2024-09-29 02:04:12 UTC


README

##JSON-RPC 2.0 for Yii2 with strict type validation of request and response data

目录

验证功能

  1. 对于没有默认值的必需参数进行验证
  2. 参数类型验证
    2.1 使用 DTO 作为结构化类型
    2.2 使用方括号表示数组类型,如 string[]、int[]、bool[] 或 DTO:ClassName[]
  3. 验证器:3.1 @notNull 标签拒绝空值(使其成为必需项)3.2 @inArray 标签限制值,如 @inArray["red","brown","yellow"]。仅适用于字符串和整数数据类型。3.3 @minSize & @maxSize 用于限制字符串长度或数字的值。

使用方法

最简单的使用方法,只需 4 步

  1. 通过 composer 安装

    在 ./composer.json 中添加到 'require' 部分

        "cranetm/yii2-json-rpc-2.0": "1.*"

    然后在控制台/终端运行

    composer update
  2. 在您的控制器中使用命名空间

    use \JsonRpc2\Controller;

    或者更改扩展类为

    class ServicesController extends \JsonRpc2\Controller
    {
        //BODY
    }
  3. 创建类似 Yii 风格的操作

    public function actionUpdate($message)
    {
        return ["message" => "hello ".$message];
    }
  4. 向控制器发送 JSON 请求(使用漂亮的 URL,无需 index.php)

    请求方法必须是 POST,并且 Content-type 必须是 application/json

    http://yoursite/services

    带有数据

    {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "update",
        "params": ["world"]
    }

    响应将如下

    {"jsonrpc":"2.0","id":1,"result":{"message":"hello world"}}

身份验证扩展

如果您想使用 JSON RPC v2.0 身份验证扩展,您可以在 \JsonRpc2\Controller 的实例中使用 \JsonRpc2\extensions\AuthTrait,如下所示

class ServicesController extends \JsonRpc2\Controller
{
    use \JsonRpc2\extensions\AuthTrait;
}

然后,您可以发送一个带有身份验证令牌的请求

{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "whoami",
    "auth": "some_access_token"
}

最后,在一个 过滤器 或在您的操作方法中,您可以调用 getAuthCredentials() 来获取请求对象的 "auth" 成员值

public function actionWhoami($message)
{
    $user = User::findIdentityByAccessToken($this->getAuthCredentials());
    if (!$user) {
        throw new \JsonRpc2\extensions\AuthException('Missing auth',
            \JsonRpc2\extensions\AuthException::MISSING_AUTH);
    }

    return ['uid' => $user->id];
}

"auth" 值的性质以及您的 User 身份类如何使用它来查找 IdentityByAccessToken 是应用特定的。例如,在简单场景中,当每个用户只能有一个访问令牌时,您可以在用户表的 access_token 列中存储访问令牌。有关相关信息,请参阅 Yii 的 REST 身份验证 文档。


参数验证

对于验证参数数据,您必须为操作方法创建 phpDoc @param 标签注释,并指定类型。
然后,这些参数数据将被转换为文档中的类型。

示例 1

(从数组或对象解析参数并进行验证)在 JSON-RPC 中,方法参数可以作为数组或对象接收,其中键是参数名称,值是参数值。

在示例 步骤 4 中,我们以数组的形式发送参数,在这种情况下,数组的第一个元素是第一个方法参数,第二个元素是第二个参数,依此类推。

但我们可以以关联对象的形式接收参数,在这种情况下,参数的顺序是不必要的。

{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "update",
    "params": {"var1":"val1","var2":"val2","message":"world"}
}

所有在方法参数中未使用的、接收到的参数都将被忽略

如果方法的参数有默认值,则可以在请求中传递。否则,此参数是必需的,如果它缺失,将抛出 \JsonRpc2\Exception::INVALID_PARAMS

示例 2

(如字符串、int、float、bool 等简单类型)让我们在 actionUpdate 中验证 $message 作为 int 值,并增加它

/**
 * @param int $message
 * @return array
 */
public function actionUpdate($message)
{
    return ["message" => ++$message];
}

对于后续请求

{"jsonrpc": "2.0","id": 1,"method": "update","params": [0.1]}
{"jsonrpc": "2.0","id": 1,"method": "update","params": ["world"]}
{"jsonrpc": "2.0","id": 1,"method": "update","params": [false]}
{"jsonrpc": "2.0","id": 1,"method": "update","params": [{}]} //empty object
{"jsonrpc": "2.0","id": 1,"method": "update","params": [[]]} //empty array

响应将是

{"jsonrpc":"2.0","id":1,"result":{"message":1}} //because all previous data converts as 0

但对于后续请求

{"jsonrpc": "2.0","id": 1,"method": "update","params": [1]}
{"jsonrpc": "2.0","id": 1,"method": "update","params": ["1world"]}
{"jsonrpc": "2.0","id": 1,"method": "update","params": [true]}
{"jsonrpc": "2.0","id": 1,"method": "update","params": [["hello", "world"]]}
{"jsonrpc": "2.0","id": 1,"method": "update","params": [{"hello": "world"}]}

响应将是

{"jsonrpc":"2.0","id":1,"result":{"message":2}}  //because all previous data converts as 1

示例 3

(结构化类型,如 数据传输对象 (DTO))如果方法中的参数数量太多,可以将它们全部传递到一个对象中。
此对象应仅包含数据,因此使用 DTO 模式。
DTO 是一个具有公开变量并具有描述类型(如 actionUpdate 中的 $message)的类的 JsonRpc2\Dto

所有 DTO 类都必须继承自 \JsonRpc2\Dto,否则将抛出 \JsonRpc2\Exception::INTERNAL_ERROR。

DTO 变量必须有一个 phpDoc @var 标签注释与类型。变量将被转换为这种类型,以及 Example 2 中的方法参数的类型。

DTO 变量的类型可以是另一个 DTO 类。

让我们创建一个具有一个字符串变量 $upper 的 Test DTO。

use \JsonRpc2\Dto;

class Test extends Dto {
    /** @var string */
    public $upper;
}

...并修改 actionUpdate 以使用 Test DTO

/**
 * @param \JsonRpc2\Dto\Test $test
 * @return array
 */
public function actionUpdate($test)
{
    return ["message" => strtoupper($test->upper)];
}

从现在起,update 动作接受 $test 参数,该参数转换为 Test 对象。因此,输入数据必须是一个对象,如

{"jsonrpc": "2.0","id": 1,"method": "update","params": [{"upper": "hello world"}]}
//or
{"jsonrpc": "2.0","id": 1,"method": "update","params": {"test": {"upper": "hello world"}}}

{"upper": "hello world"} 将被转换为具有变量验证的 \JsonRpc2\Test 对象。因此,响应将是

{"jsonrpc":"2.0","id":1,"result":{"message":"HELLO WORLD"}}

示例 4

(数组类型)为了更好的验证,'array' 作为变量或参数类型已被弃用,您必须使用方括号与简单类型或 DTO 之一。
您可以在操作或 DTO 中使用这些数组,并且所有参数数据都将递归验证。

'Update' 操作

/**
 * @param \JsonRpc2\Dto\Test[] $tests
 * @param string[] $messages
 * @return array
 */
public function actionUpdate($tests, $messages)
{
    //BODY
}

组合 DTO

use \JsonRpc2\Dto;

class Combined extends Dto {
    /** @var string[] */
    public $messages;

    /** @var \JsonRpc2\Dto\Test[] */
    public $tests;
}

响应数据验证

为了减少不必要的功能以将数据类型简化为从服务器接收的数据,您必须在服务器端验证数据。
为此,您必须添加一个带有数据类型的 @return 标签在 phpDoc 注释中。
然后数据将被转换为给定的类型。
它与 @param@var 验证一样工作。

DTO User 在下一个示例中使用

use JsonRpc2\Dto;

class User extends Dto
{
    /** @var int */
    public $id;

    /** @var string */
    public $name;

    /** @var string */
    public $type = 'user';

    /** @var string */
    public $rights="";
}

示例 5

(响应验证):让我们创建一个名为 get-users 的操作,该操作模拟从存储中检索数据并返回用户数组的操作

/**
 * @return \JsonRpc2\Dto\User[]
 */
public function actionGetUsers()
{
    return [
        [
            "id" => "1",
            "name" => "Marco Polo",
            "type" => "admin",
        ],
        [
            "id" => "234",
            "name" => "John Doe",
            "rights" => "settings"
        ]
    ];
}

响应数组中的每个元素都将转换为 User DTO

//request
{"jsonrpc": "2.0","id": 1,"method": "get-users","params": []}

//response
{"jsonrpc":"2.0","id":1,"result":[{"id":1,"name":"Marco Polo","type":"admin","rights":""},{"id":234,"name":"John Doe","type":"user","rights":"settings"}]}

即使响应数组中缺少某些值,数据也将转换为具有 DTO 中描述的所有变量的 User 类型

验证器

有一系列验证器可以更改值或检查它是否符合某些规则(或两者都做)。要使用它,只需在需要的变量或属性后面的新行中写下它的名称。例如

    /**
     * @var int
     * @inArray[1,2]
     */
    public $example=0;

这里我们有一个 inArray 验证器用于 $example 属性。脚本尝试找到名为 JsonRpc2\Validator\ValidateInArray 的类,并运行 validate() 方法(见 JsonRpc2\Validator 文件夹)。如果发生验证错误,则响应对象将有数据属性,其中包含说明

{
    "cause":"rights",       // failed property
    "type":"inArray",       // validator name
    "value":0,              // passed value
    "restriction":'"1","2"' // active restrictions
}

空值和 @notNull 标签

DTO 的值可以是 NULL,如果没有初始化(与 php 中的情况相同)。如果您需要默认空值但不是 NULL,请定义它,并且如果您传递 NULL,则定义的默认值将使用(例如示例中的空字符串)。

    /**
     * @var string
     */
    public $rights="";

但在许多情况下,您需要必需的值,该值必须传递到 DTO 中。在这种情况下,清除(如果存在)默认值并使用 @notNull 标签。

让我们将 User 的 rights 变量更新为非 NULL,并且没有默认值(必需)

    /**
     * @var string
     * @notNull
     */
    public $rights;
//request
{"jsonrpc": "2.0","id": 1,"method": "get-users","params": []}

//response
{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"JsonRpc2\\Dto\\User::$rights is required and cannot be Null.","data":{"cause":"rights","value":null,"type":"notNull","restriction":""}}}

如我们所见,现在 rights 变量是必需的。

值限制和 @inArray 标签

有许多情况,其中值可能仅限于几个变体,并且应该验证它们的存在。
它是如何工作的?
让我们为变量User的权限设置限制,并尝试发起请求。

    /**
     * @var string
     * @inArray["dashboard","settings"]
     */
    public $rights;
//request
{"jsonrpc": "2.0","id": 1,"method": "get-users","params": []}

//response
{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"Value '' is not allowed for JsonRpc2\\Dto\\User::$rights property. Allowed values is 'dashboard','settings'","data":{"cause":"rights","value":"","type":"inArray","restriction":"\"dashboard\",\"settings\""}}}

糟糕... Marco Polo发生了错误,关于权限中的空值转换为字符串后变成了空字符串 ""。
但是存在没有空字符串的限制(["dashboard","settings"]),所以我们遇到了错误。
为了防止这种情况,你**必须**为$rights定义允许的默认值,或者添加@null标签,或者更新限制(将""添加到inArray列表中),或者你可以为Marco Polo定义允许的权限。

....
   return [
        [
            "id" => "1",
            "name" => "Marco Polo",
            "type" => "admin",
            "rights" => "dashboard",
        ],
...

并且响应将是

{"jsonrpc":"2.0","id":1,"result":[{"id":1,"name":"Marco Polo","type":"admin","rights":"dashboard"},{"id":234,"name":"John Doe","type":"user","rights":"settings"}]}

使用 @minSize & @maxSize 标签限制值

这些标签限制字符串或数字的长度。

    //can be used together
    /**
     * @var string
     * @minSize 15
     * @maxSize 50
     */
    public $name;

    //...or separatly
    /**
     * @var string
     * @minSize 15
     */
    public $name;

    //for numbers
    /**
     * @var int
     * @minSize 100
     * @minSize 500
     */
    public $money;

如果值超出这个范围,你会遇到错误

{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"For JsonRpc2\Dto\User::$money allowed min size is 100","data":{"cause":"money","value":37,"type":"minSize","restriction":"100"}}}

CORS 支持

从1.2.5版本开始,扩展支持CORS请求。你可以通过将CORS过滤器附加到控制器作为行为来使用CORS过滤器,请按照以下说明操作这里



#####如果你遇到功能问题,不要害怕在这里注册。

#####谢谢。