bognerf/rest-grabber

消费REST API

v2.3.0 2021-12-03 09:25 UTC

README

Coverage Latest Stable Version Total Downloads License

与REST API协同工作,并确保JSON响应中某些元素的存在和有效性。

目录

通过Composer

$ composer require bognerf/rest-grabber

用法

基本用法(无验证或生成派生对象(值对象))非常简单

use Bognerf\RestGrabber\Grabber;
use Bognerf\RestGrabber\Url;

$url = new Url('https://reqres.in/api/unknown/2');
$grabber = new Grabber($url);
$contents = $grabber->get()->grab()->data();

您将根据 https://reqres.in/api/unknown/2 的响应获得一个数组;

全局验证规则

您可以通过点分隔的键的数组来定义JSON响应中的必填值。此外,您可以传递一个数组,其中包含应匹配给定键值的 约束。RestGrabber 依赖于 Symfony的约束库

use Bognerf\RestGrabber\Grabber;
use Bognerf\RestGrabber\Url;

$url = new Url('https://reqres.in/api/users/2');
$grabber = new Grabber($url);
$grabber->getHandler()->setObligatoryFields([
    'data' => [
        new \Symfony\Component\Validator\Constraints\Count(['min'=>5])
    ],
    'data.email' => [
      new \Symfony\Component\Validator\Constraints\Email()
    ]
]);
$grabber->get()->grab();

上面的示例将查询 https://reqres.in/api/users/2 并确保根级元素 data 至少包含五个子元素。此外,正如 data.email 所示,必须在 data 下存在一个元素 email,其语法必须符合电子邮件地址。

值对象

RestGrabber从我们的JSON中的某些子元素(甚至可能是根元素,如果您希望的话)生成值对象。为了使其正常工作,我们必须将一个 Handler 传递给我们的RestGrabber实例。默认情况下,库提供了一个通用的处理器 Bognerf\RestGrabber\Handlers\PlainJson。所有处理器都必须扩展抽象类 Bognerf\RestGrabber\Handler

如何使用它们

考虑以下 JSON示例1(从 https://reqres.in/api/unknown/ 获得)

{
  "page": 1,
  "per_page": 3,
  "total": 12,
  "total_pages": 4,
  "data": [
    {
      "id": 1,
      "name": "cerulean",
      "year": 2000,
      "color": "#98B2D1",
      "pantone_value": "15-4020"
    },
    {
      "id": 2,
      "name": "fuchsia rose",
      "year": 2001,
      "color": "#C74375",
      "pantone_value": "17-2031"
    },
    {
      "id": 3,
      "name": "true red",
      "year": 2002,
      "color": "#BF1932",
      "pantone_value": "19-1664"
    }
  ]
}

data 下有三种对象。使用RestGrabber,您可以定义 data 作为值对象的根元素(使用点符号也可以进行更深的嵌套,例如 data.sub-element),自动解析它们并为每个条目创建一个值对象。让我们看看

use Bognerf\RestGrabber\Grabber;
use Bognerf\RestGrabber\Url;

$url = new Url('https://reqres.in/api/unknown');
$grabber = new Grabber($url);

$grabber->getHandler()->addValueObjectsRoot([
    'data' => []
]);
$grabber->get()->grab();
$valueObjects = $grabber->valueObjects('data');

我们依赖于内置的处理器 PlainJson。现在 $valueObjects 是一个包含三个值对象的数组,可以像这样使用

foreach ($valueObjects as $vo) {
    echo $vo->getName() . PHP_EOL;
}

getName() 是一个魔法获取器函数。您可以通过 get 加上 元素的首字母大写 来检索值对象的任何元素。

此外,还有其他常见的魔法获取器

foreach ($valueObjects as $vo) {
    echo $vo->color . PHP_EOL;
}
JSON示例2

您不仅限于只有一个值对象根,可以有更多。考虑我们稍作修改的JSON

{
  "page": 1,
  "per_page": 3,
  "total": 12,
  "total_pages": 4,
  "data": [
    {
      "id": 1,
      "name": "cerulean",
      "year": 2000,
      "color": "#98B2D1",
      "pantone_value": "15-4020"
    },
    {
      "id": 2,
      "name": "fuchsia rose",
      "year": 2001,
      "color": "#C74375",
      "pantone_value": "17-2031"
    },
    {
      "id": 3,
      "name": "true red",
      "year": 2002,
      "color": "#BF1932",
      "pantone_value": "19-1664"
    }
  ],
  "more-data": [
    {
    "id": 1,
    "name": "Florian"
    },
    {
    "id": 2,
    "name": "Katharina"
    }
  ]
}

如您所见,我们有多于一个潜在的值对象根,即 datamore-data。只需将 more-data 添加为第二个值对象根即可

use Bognerf\RestGrabber\Grabber;
use Bognerf\RestGrabber\Url;

$url = new Url('https://reqres.in/api/unknown');
$grabber = new Grabber($url);

$grabber->getHandler()->addValueObjectsRoot([
    'data' => []
]);

$grabber->getHandler()->addValueObjectsRoot([
    'more-data' => []
]);

$grabber->get()->grab();
$valueObjectsData = $grabber->getHandler()->valueObjects('data');
$valueObjectsMoreData = $grabber->getHandler()->valueObjects('more-data');

值对象验证规则

除了为整个JSON定义全局必填值之外,您还可以为每个值对象根中的元素定义验证器。再次使用我们的REST API https://reqres.in/api/unknown,一个根级元素 data 包含多个对象可以作为值对象的根级。记住,值对象的根也使用点符号表示。让我们看看如何实现这一点

use Bognerf\RestGrabber\Grabber;
use Bognerf\RestGrabber\Url;

$url = new Url('https://reqres.in/api/unknown');
$grabber = new Grabber($url);

$grabber->getHandler()->addValueObjectsRoot([
    'data' => [
        'id' => [],
        'name' => [
            new \Symfony\Component\Validator\Constraints\Length(['min' => 3, 'max' => 128])
        ],
        'pantone_value' => [
            new \Symfony\Component\Validator\Constraints\Regex([
                'pattern' => '/^([0-9]){2}\-([0-9]){4}$/'
            ])
        ]
    ]
]);
$grabber->get()->grab();
$valueObjects = $grabber->valueObjects('data');

上述示例将查询 https://reqres.in/api/unknown 并验证根级元素 data 是否存在且至少包含两个元素。我们的ValueObjects的根也将设置为 data。在data中,每个元素必须有一个没有其他约束的 id 元素,以及一个 name 元素,其长度至少为三个字符,最多为100个字符。最后,$grabber->valueObjects('data') 将返回一个ValueObjects数组,每个ValueObjects都经过检查以满足我们的约束。

自定义处理器

在某些用例中,创建自定义Handler是有意义的。例如,我们将使用Cloudflare内容分发网络的API cdnjs.com

为了确保CDNJS的JSON响应包含我们依赖的所有关键元素,请创建自定义Handler如下(请记住,在扩展基础Handler的构造函数时,不要忘记调用 parent::__construct()

class CdnjsHandler extends \Bognerf\RestGrabber\Handler
{
    public function __construct()
    {
        parent::__construct();
        $this->obligatoryFields = [
            'assets' => [],
            'repository.type' => [
                new \Symfony\Component\Validator\Constraints\EqualTo(['value' => 'git']),
            ],
        ];

        $this->addValueObjectsRoot([
            'assets' => [
                'version' => [
                    new \Symfony\Component\Validator\Constraints\NotBlank(),
                ],
                'files' => [
                    new \Symfony\Component\Validator\Constraints\Count(['min' => 2])
                ]
            ]
        ]);
    }

}

有趣的是,handler定义了自己的必需元素和验证规则。我们要求JSON响应包含一个 assets 元素以及一个 repository.type 元素,其值应为 git。后者是点表示法访问深层元素的绝佳例子。比较来自 CDNJS 的实际JSON。

此外,assets 下的集合或列表将构成我们的单个ValueObjects根,确保每个都包含一个 version 元素(必须存在且不为空或空白或null),以及一个 files 元素,它必须是一个包含至少两个元素的集合。

现在让我们将我们的新自定义handler投入使用

use Bognerf\RestGrabber\Grabber;
use Bognerf\RestGrabber\Url;

$url = new Url('https://api.cdnjs.com/libraries/axios');
$grabber = new Grabber($url);

$grabber->setHandler(new CdnjsHandler());

$grabber->get()->grab();
$valueObjects = $grabber->valueObjects('assets');

dump($valueObjects);

与缓存协同工作

RestGrabber可以通过 RestGrabber::setCache() 接收一个兼容PSR-16的CacheInterface。我们将使用ZendCache,因此需要要求一些依赖项

$ composer require zendframework/zend-cache
$ composer require zendframework/zend-serializer

但请记住,您可以使用任何兼容PSR-16的CacheInterface。它不必是Zend的。

$storage = StorageFactory::factory([
    'adapter' => [
        'name' => 'filesystem',
        'options' => [
            'cache_dir' => '/tmp/rest-grabber',
        ],
    ],
    'plugins' => [
        'serializer',
    ],
]);

$cache = new SimpleCacheDecorator($storage);

$url = new Url('https://api.cdnjs.com/libraries/axios');
$grabber = new Grabber($url);
$grabber->setCache($cache);
echo ($grabber->isCached() ? "Hit":"Missed");
$grabber->setHandler(new \RestGrabberTestbed\Handlers\CdnjsHandler());

$grabber->get()->grab();
$valueObjects = $grabber->valueObjects('assets');
echo ($grabber->isCached() ? "Hit":"Missed");

测试

$ composer test

安全

如果您发现任何安全相关的问题,请通过电子邮件fb@florianbogner.de联系,而不是使用问题跟踪器。

鸣谢

许可

MIT许可证(MIT)。请参阅 许可证文件 了解更多信息。