ratfactor/hummingjay

此包已被废弃,不再维护。未建议替代包。

一个用于创建hm-json REST API的库/框架。处理超媒体、路由和HTTP方法。

v4.0.2 2021-10-30 20:42 UTC

This package is auto-updated.

Last update: 2023-09-29 01:43:00 UTC


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中的BookReviewsCollection资源类以获取示例。

$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”项目