ratfactor / hummingjay
一个用于创建hm-json REST API的库/框架。处理超媒体、路由和HTTP方法。
README
已移动!大家好,我正在将我的仓库迁移到http://ratfactor.com/repos/,并在GitHub上将其设置为只读("存档")。感谢,-Dave
概述
HummingJay是一个PHP 5.5+库,用于使用hm-json格式(待补充:hm-json需要一个独立的规范页面!)创建REST API,向客户端提供超媒体和JSON数据。它具有路由、超媒体生成、JSON数据I/O和处理HTTP通信的方法。
参见https://github.com/ratfactor/hm-json-browser
安装
composer require ratfactor/HummingJay
小型示例
<?php
require "vendor/autoload.php";
class Foo extends HummingJay\Resource{}
$api = new HummingJay\HummingJay(["/foo"=>"Foo"]);
?>
此示例过于简单。但它完全有效,展示了HummingJay如何路由请求:URI路径"/foo"解析为资源Foo。
演示
请查看源代码中的大量注释的demo/index.php文件,以获取创建资源的更详细示例。还可以参见下面的"运行测试/演示"。
路由
HummingJay\HummingJay类的构造函数接受一个路由数组。格式非常简单:数组的键是路由的URI,值是给定路由的资源类名。
以下是一个使用PHP的nowdoc字符串格式的示例
$api = new HummingJay\HummingJay([
"/" => "MyRoot"
"/foo" => "Foo"
"/foo/bars" => "BarCollection"
"/foo/bars/{bar_id}" => "SpecificBar"
]);
在这里,我们可以看到我们定义了四个可能的URI。其中之一/foo/bars/{bar_id}有一个参数,它将匹配符合该模式的URI(例如/foo/bars/31或/foo/bars/Cheers)。
这四个URI将由指定的资源类的一个实例处理。当你尝试访问URI /foo时,控制权将传递给由Foo类定义的资源。
匹配到URI结尾的参数
有一个特殊的语法{foo--->}用于创建一个匹配URI结尾的所有内容的最终参数。
示例
$api = new HummingJay\HummingJay(["/foo/{string--->}" => "HelloFoo"]);
这创建了一个只有一个路由的API,该路由将匹配以下URI
/foo/Hello-World
/foo/etc/rc.d/chicken.txt
在这两种情况下,名为string的参数值分别等于字符串'Hello-World'和'etc/rc.d/chicken.txt'。
有关如何访问URI参数的说明,请参见下面的"从$server获取请求数据"。
创建资源
要创建一个新的资源,扩展HummingJay\Resource类。示例
class Foo extends HummingJay\Resource{
$title = "The Foo Resource!";
$description = "I don't do much. Try a GET to get a list of stuff!";
}
如所示,建议您自定义资源的标题和描述。这些将在理解hm-json格式超媒体的应用程序(如hm-json浏览器)中可见。
如果资源不应自动尝试解码JSON请求数据,您可以添加一个可选设置
$decodeJson = false;
添加所需的HTTP方法处理器(支持:OPTIONS,GET,PUT,POST,DELETE,PATCH,HEAD)。以下是一个返回包含名为"foo_id"的参数的JSON编码对象的GET请求。
class Foo extends HummingJay\Resource{
public function get($server){
$server->addResponseData(["foo_id"=>"1003"]);
return $server;
}
}
有关此处理程序示例的更多解释,请继续阅读。
注意:HummingJay提供了一个默认的OPTIONS方法。您可以扩展它以添加功能。请参见demo/index.php中的Book和ReviewsCollection资源类以获取示例。
$server对象
传递给每个方法处理器的$server参数是\HummingJay\Server类的一个实例。它是HummingJay用于所有请求和响应功能的接口(因此是Web服务器的抽象)。
从$server获取请求数据
当传递给方法处理器时,$server包含以下关于传入HTTP请求的属性
| 属性 | 描述 |
|---|---|
uri |
请求资源的URI |
params |
从URI中获取的参数关联数组 |
method |
使用的HTTP方法,例如POST |
requestData |
反序列化的JSON数据(如果没有则为null) |
rawRequestData |
原始请求体(字符串) |
jsonError |
简短描述错误或'none'的字符串 |
以下是一个示例,该示例从请求体中获取URI参数和一些JSON数据
// route string: /foo/bar/{bar_id} - Foo
// request: PUT /foo/bar/74
// request body: {'bardata':[3,6,4,9]}
class Foo extends \HummingJay\Resource{
public function put($server){
$mybar = $server->params['bar_id']; // 74
if($requestData !== null){
$bars->update(
$mybar,
$requestData->bardata
);
}
}
}
使用$server构建响应
当从方法处理程序返回$server时,它包含您希望发送回客户端的HTTP响应头和体的指令。
$server有以下方法用于修改即将发出的HTTP响应
| 方法 | 描述 |
|---|---|
setStatus($num) |
设置HTTP状态码 |
addHeader($str) |
添加自定义HTTP头 |
addResponseData($data) |
添加任何PHP数据(将被JSON编码) |
hyperTitle($str) |
设置超媒体标题 |
hyperDescription($str) |
设置超媒体描述 |
hyperLink($data) |
添加超媒体链接 |
hyperStatus($num, $str) |
使用超媒体设置HTTP状态码 |
$server->setStatus($num)
class Foo extends \HummingJay\Resource{
public function get($server){
$server->setStatus(500);
return $server;
}
}
请参阅src/Server.php以获取HummingJay理解的所有HTTP状态码的完整列表。您可以自由使用列表中未列出的代码,但它不会有文本描述(这是HTTP合法的)。
请参阅hyperStatus()以获取向人类和计算机报告响应状态的一种更友好方式。
$server->addHeader($str)
class Foo extends \HummingJay\Resource{
public function get($server){
$server->addHeader("X-Custom-Message: Hello World!");
return $server;
}
}
这可以是您喜欢的任何内容。注意,HummingJay已经自动为您设置了JSON的Content-Type。
$server->addResponseData($data)
class Foo extends \HummingJay\Resource{
public function get($server){
$server->addResponseData(['foo'=>'bar']);
return $server;
}
}
在上面的示例中,添加到响应中的关联数组将被转换为以下响应体并发送回客户端
{ "foo": "bar" }
HummingJay依赖于PHP的内置json_encode()函数。它有合理的规则来处理顺序数组、关联数组、对象等。
连续调用addResponseData()将使用PHP的内置array_merge()函数合并数据。
$server->addResponseData(["dog"=>"Sparky"]);
$server->addResponseData(["cat"=>"Fuzzy"]);
return $server;
结果是响应体
{ "dog": "Sparky", "cat": "Fuzzy" }
$server->hyperTitle($str) 和 hyperDescription($str)
class Foo extends \HummingJay\Resource{
public function get($server){
$server->hyperTitle("The Foo Resource");
$server->hyperDescription("I contain all of the FOO!");
return $server;
}
}
一旦添加了任何标题、描述或超链接等超媒体属性,$server对象就知道返回hm-json超媒体。上面的示例将产生以下响应体
{
"hypermedia":{
"title": "The Foo Resource",
"description": "I contain all of the FOO!"
}
}
$server->hyperLink($data)
class Foo extends \HummingJay\Resource{
public function get($server){
$server->hyperLink([
"method"=>"GET",
"title"=>"Woggle",
"href"=>'/woggles/woggle',
"rel"=>"item"
]);
return $server;
}
}
此示例将在JSON响应的超媒体属性中的链接数组中添加链接
{
"hypermedia": {
"links": [
{
"method": "OPTIONS",
"title": "books",
"href": "/books",
"rel": "child"
}
]
}
}
重要的是要理解,HummingJay提供的默认OPTIONS方法为您的API生成了hm-json超媒体链接。其他方法不返回超媒体,除非您调用了其中一个hyper*方法。
$server->hyperStatus($num, $str)
class Foo extends \HummingJay\Resource{
public function get($server){
$server->hyperStatus(410, "This resource was removed forever.");
return $server;
}
}
继续阅读以下部分,以获取此示例的更紧凑版本。
此示例将返回一个HTTP 410状态和以下消息体
{
"hypermedia": {
"title": "410 Gone",
"description": "This resource was removed forever."
}
}
您可以使用addResponseData()提供更细粒度的响应,以配合HTTP状态码。
$server方法返回$server实例
$server对象的全部公共API方法都返回$server本身的实例。这允许您有更紧凑的响应(这在您有很多保护语句时可能会有很大区别)。以下是一个使用hyperStatus()的示例
class Foo extends \HummingJay\Resource{
public function get($server){
return $server->hyperStatus(410, "This resource was removed forever.");
}
}
上述所有方法示例都可以这样缩短。此功能还允许这些方法的链式调用。请随意实验!
使用halt()停止资源
您可以使用资源的构造函数作为资源的“保护器”。这使得您可以在一个地方检查所有方法的请求的有效性。要使资源立即发送其响应而无需调用任何HTTP方法处理程序,只需调用其halt()方法。以下是一个示例
class Foo extends Resource{
public function __construct($server){
$id = $server->params["foo_id"];
if(!$db->isValidFoo($id)){
$server->hyperStatus(404, "Could not find a foo with ID $id.");
$this->halt();
}
}
}
请参阅Books演示(demo/index.php)以获取此行为的完整示例。
运行测试/演示
如果您已安装PHPUnit,您可以使用以下命令运行单元测试:
phpunit
本项目还包括一个Vagrantfile,您可以使用它来安装和配置一个虚拟机,其中包含PHP 5.6、PHPUnit和Apache网络服务器,并配置为显示包含HummingJay演示网站。 了解Vagrant。
安装Vagrant后,您可以运行以下命令来执行单元测试
> vagrant up
> vagrant ssh
$ cd /vagrant
$ phpunit
在虚拟机运行时,您还可以访问以下演示网站:https://:8787/browser.html *见以下说明!
该演示使用名为 hm-json Browser 的工具来浏览一个微型Books集合API。
演示说明
由于Apache或PHP配置中某个隐藏的非常令人烦恼的设置,除非您使用以下URL,否则您将无法完全浏览演示:https://:8787/browser.html#/index.php
显然,这个版本的Apache配置为自行处理OPTIONS方法请求,除非它看到mod_php将处理请求(它只有当"index.php"实际上 包含 在提交的URL中时才会确定)。这个美妙的功能让我在家庭时间上浪费了宝贵的时间,我希望它能回来。
我不知道这个设置在哪里。我已经绞尽脑汁地grep和Google了。我大部分时间都在追逐这类垃圾,而不是真正编写优秀的代码。如果有人有追踪Apache此类决策过程的万无一失的方法,我将非常乐意了解。否则,让我们都为每年在这些令人愉快的Web开发秘密上浪费的数百万小时点上一支蜡烛。
许可证
MIT许可证(MIT)
版权所有(c)2015 David Gauer
特此授予任何获得本软件及其相关文档文件(“软件”)副本的任何人免费处理软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本,以及允许向提供软件的人这样做,前提是遵守以下条件
上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。
软件按“现状”提供,不提供任何形式的保证,无论是明示的、暗示的、包括但不限于适销性、特定用途和侵权保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任负责,无论该索赔、损害或其他责任是由于合同、侵权或其他原因引起的,与软件或其使用或其他交易有关。
版本历史
我打算遵守语义版本控制规则。
| 版本 | 日期 | 描述 |
|---|---|---|
| 4.0.2 | 2021-10-30 | 恢复v4.0.0更改(之前认为在bitbucket中丢失) |
| 4.0.1 | 2021-07-28 | 从Mercurial转换为Git |
| 4.0.0 | 2016-11-30 | 将路由表格式从字符串更改为数组 |
| 3.3.1 | 2015-12-18 | 向响应数据添加null现在是安全的 |
| 3.3.0 | 2015-12-10 | 服务器对象方法现在返回服务器实例 |
| 3.2.0 | 2015-12-08 | 添加了'匹配到末尾'的最终参数语法 |
| 3.1.0 | 2015-11-20 | 向资源对象添加了$decodeJson选项 |
| 3.0.2 | 2015-08-12 | 测试并重构Resource::options(),修复了extractApiUri()中的错误 |
| 3.0.1 | 2015-07-29 | 微调错误,完成测试覆盖率 |
| 3.0.0 | 2015-07-25 | 主要重构(具有破坏API更改)(更清晰,更可测试) |
| 2.0.1 | 2015-07-24 | 添加Vagrant VM用于测试/演示,重构并添加更多测试 |
| 2.0.0 | 2015-07-18 | 重构,添加Request类,更改请求负载接口 |
| 1.1.1 | 2015-06-19 | 删除仅针对开发的PHPUnit依赖项(不要通过Composer安装) |
| 1.1.0 | 2015-06-19 | 向请求对象添加JSON解码的负载,更新README |
| 1.0.0 | 2015-03-01 | HummingJay 已在实际项目中使用 |
| 0.1.1 | 2015-02-13 | 移除早期原型遗留的bug |
| 0.1.0 | 2015-02-10 | 初始发布版本。取代了之前的“hm-json ResourcePhp”项目 |