cranetm / yii2-json-rpc-2.0
为 Yii2 提供严格类型验证的 JSON RPC 2.0
Requires
- php: >=5.4.0
- yiisoft/yii2: *
This package is not auto-updated.
Last update: 2024-09-14 16:24:11 UTC
README
##JSON-RPC 2.0 for Yii2 with strict type validation of request and response data
目录
- 验证功能
- 使用方法
- 身份验证扩展
- 参数验证
- 示例 1
- 示例 2
- 示例 3
- 示例 4
- 响应数据验证
- 示例 5
- 验证器
- 空值和 @notNull 标签
- 值限制和 @inArray 标签
- 使用 @minSize & @maxSize 标签限制值
- CORS 支持
验证功能
- 如果参数没有默认值,则对其进行必需参数验证
- 参数类型验证
2.1 使用 DTO 作为结构化类型
2.2 使用方括号表示数组类型,如 string[], int[], bool[] 或 DTO: ClassName[] - 验证器:3.1 @notNull 标签拒绝空值(使其成为必需的)3.2 @inArray 标签限制值,如 @inArray["red","brown","yellow"]。仅适用于字符串和 int 数据类型。3.3 @minSize & @maxSize 限制字符串的长度或数字的值。
使用方法
最简单的使用方法,只需 4 步
-
通过 composer 安装
在 ./composer.json 中将以下内容添加到 'require' 部分
"cranetm/yii2-json-rpc-2.0": "1.*"
并在控制台/终端运行
composer update
-
在您的控制器中使用命名空间
use \JsonRpc2\Controller;
或更改扩展类为
class ServicesController extends \JsonRpc2\Controller { //BODY }
-
创建类似 Yii 风格的操作
public function actionUpdate($message) { return ["message" => "hello ".$message]; }
-
向控制器发送 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
(简单类型如字符串、整型、浮点型、布尔型) 让我们在 actionUpdate 中验证 $message 作为整型值,并将其增加
/** * @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)的公共变量的类。
所有 DTO 类都必须继承自 \JsonRpc2\Dto,否则将抛出 \JsonRpc2\Exception::INTERNAL_ERROR。
DTO 变量必须有一个带有类型的 phpDoc @var 标记注释。变量将被转换为这种类型,以及在 示例 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 中使用这些数组,并且所有参数数据都将递归地进行验证。
更新 动作
/** * @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; }
响应数据验证
为了减少不必要的功能并将其带到来自服务器的数据类型,必须在服务器端验证数据。
为此,你必须在 phpDoc 注释中添加带有数据类型的 @return 标记。
然后数据将被转换为给定类型。
这与 @param 或 @var 验证的效果相同。
DTO 用户将在下面的示例中使用
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 类型
验证器
有一组验证器可以更改值或检查它是否符合某些规则(或两者),要使用它,只需在 phpdoc 中在所需的变量或属性后写上其名称。例如
/** * @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 }
NULL 值和 @notNull 标签
DTO 的值可以是 NULL,如果它们没有初始化(与 php 中的情况相同)。如果你需要默认空值而不是 NULL,定义它,并且如果传递 NULL,则将使用定义的默认值(如示例中的空字符串)
/** * @var string */ public $rights="";
但是在许多情况下,你需要一个必须通过 DTO 传递的必填值。在这种情况下,清除(如果存在)默认值并使用 @notNull 标签。
让我们将 User 的权限变量更新为非空且无默认值(必填)
/** * @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":""}}}
正如我们所看到的,权限变量现在是必填的。
值限制和 @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过滤器作为行为附加到控制器上使用,只需遵循以下说明这里
#####如果您在功能方面遇到问题,请不要害怕在此处注册。
#####谢谢。