monomelodies / monki
PHP5 API 生成工具
Requires
- php: >=7.1
- ext-json: *
- ext-pcre: *
- ext-reflection: *
- ext-spl: *
- laminas/laminas-diactoros: ^2.2
- league/fractal: ^0.14.0
- monolyth/reroute: ^5.0.0
- zeptech/annotations: ^1.2
Requires (Dev)
- gentry/gentry: ^0.13.12
- gentry/toast: ^0.1.1
- toast/unit: ^2.0
This package is auto-updated.
Last update: 2024-09-15 16:21:25 UTC
README
简单的API引导程序。
Monki是一个库,允许您快速为项目添加基本API。提供API变得越来越重要,原因如下:
- 它允许您的库或项目轻松成为“物联网”的一部分,允许其他库或应用程序访问它;
- 对于使用AngularJS等框架的SPA,提供API是必需的;
- 即使在编写传统的PHP应用程序时,使用API也可以抽象出数据库等许多工作。
安装
Composer(推荐)
$ cd /path/to/project
$ composer require monomelodies/monki
手动
下载或克隆仓库,并将/path/to/monki/src添加到PSR-4自动加载器的Monki\\命名空间。
设置
Monki使用league/pipeline实现了流水线。
<?php use Monki\Api; $monki = new Monki('/base/url/of/api/');
然后,您的前端控制器(例如index.php)可以将其添加到其流水线中(有关更多信息,请参阅league/pipeline文档)。
<?php $pipeline = (new Pipeline) ->pipe($monki);
如果您没有使用流水线,您还可以调用Monki对象并检查其返回值。
<?php use Psr\Http\Message\ResponseInterface; use Zend\Diactoros\ServerRequestFactory; $response = $monki(ServerRequestFactory::fromGlobals()); if ($response instanceof ResponseInterface) { // Emit the response } else { // No an API URL; use e.g. your router to determine further handling. }
对于输出,您可以使用例如Zend\Diactoros\Response\SapiEmitter。Diactoros是Monki的要求,因此您已经拥有它。但您可以使用其他任何东西。
添加状态和响应
内部,Monki的流水线利用了Monolyth\Reroute路由器。Reroute允许您使用when('url')和then('statename', callable)指定对HTTP请求的期望处理方式。此外,您还可以指定post、put和delete的可调用函数,并可以向流水线添加阶段,例如检查用户对某些功能的访问权限。由于Monki上的when方法返回实际的底层路由器,因此您可以手动指定所有这些。
但是,通常任何结构良好的API都将遵循更类似于以下模式的模式
GET /api/user/ <- browse all users
POST /api/user/ <- create a new user
GET /api/user/:id/ <- retrieve a specific user
POST /api/user/:id/ <- update a specific user
DELETE /api/user/:id/ <- delete a specific user
这正是Monki旨在使其易于引导的“默认”API行为!它使用crud方法来实现这一点
<?php use Monomelodies\Monki\Handler\Crud; class MyHandler extends Crud { } $monki->crud('/api/user/', new MyHandler);
在上面的示例中,我们简单地传递了一个Crud处理程序接口的实例。crud方法的返回值还可以流水线,例如用于访问检查。第一个参数是端点的基路径,第二个是资源特定端点的路径。
如果您尝试访问URL /api/user/,您不会得到用户列表,而是会发现API路由器返回NULL。这是有道理的,因为我们的处理程序实际上没有指定任何处理方式!嘿,别急,Monki有一些默认设置,但不是先知...
让我们首先让它对browse-style请求做出响应
<?php use Monomelodies\Monki\Handler\Crud; class MyHandler extends Crud { public function browse() { // This should e.g. do a database query in real life: $users = ['Marijn', 'Linus', 'Bill']; return $this->jsonResponse($users); } }
默认支持的处理器列表如下
GET 处理器POST 处理器GET 处理器POST 处理器DELETE 处理器
要为多个表重用您的处理器,例如,您可以在构造函数中传递表名并将其私下存储。
完整示例
以下是一个使用Quibble\Query进行数据库查询的完整、工作示例(有关Quibble查询构建器的更多信息,请参阅他们的文档)。
<?php use Quibble\Dabble\Adapter; use Zend\Diactoros\Response\EmptyResponse; class MyHandler extends Crud implements Browse, Create, Retrieve, Update, Delete { private $db; private $table; public function __construct(Adapter $db, $table) { $this->db = $db; $this->table = $table; } public function browse($id = null) { $items = $this->db->selectFrom($this->table) ->fetchAll(PDO::FETCH_ASSOC); return $this->jsonResponse($items); } public function create($id = null) { $this->db->insertInto($this->table) ->execute($_POST); $id = $this->db->lastInsertId($this->table); return $this->retrieve($id, 201); } public function retrieve($id, $status = 200) { $item = $this->db->selectFrom($this->table) ->where('id = ?', $id) ->fetch(PDO::FETCH_ASSOC); return $this->jsonResponse($item, $status); } public function update($id) { $this->db->updateTable($this->table) ->where('id = ?', $id) ->execute($_POST); return $this->retrieve($id); } public function delete($id) { $this->db->deleteFrom($this->table) ->where('id = ?', $id) ->execute(); return $this->emptyResponse(204); } } // Assuming $user contains the currently logged in user... $monki->crud('/api/user/', '/:id/', new MyHandler($db, 'user')) ->pipe(function ($payload) use ($user) { if ($user->name != 'Marijn') { // Bad user! No access. return new EmptyResponse(403); } return $payload; });
显然,这相当简单,因为它没有进行任何错误检查,但您已经了解了这种方法。使用此处理器类,您可以快速设置对一些数据库表的处理。
<?php $check = function ($payload) use ($user) { if ($user->name != 'Marijn') { // Bad user! No access. return new EmptyResponse(403); } return $payload; }; $monki->crud('/api/user/', '/:id/', new MyHandler($db, 'user'))->pipe($check); $monki->crud('/api/message/', '/:id/', new MyHandler($db, 'message'))->pipe($check); $monki->crud('/api/foo/', '/:id/', new MyHandler($db, 'foo'))->pipe($check); $monki->crud('/api/bar/', '/:id/', new MyHandler($db, 'bar'))->pipe($check); // This endpoint is open for the world (usually a bad idea ;)): $monki->crud('/api/baz/', '/:id/', new MyHandler($db, 'baz')); // ...
转换响应
与在处理器构造函数中传递PDO适配器和表名类似,也可以传递一个转换器(或通过其他方式注入)。转换器是类或可调用对象,用于在将原始数据“倾倒”到开放环境中之前对其进行“按摩”。这是你自己需要实现的事情;Monki不希望做出假设。但我们推荐使用league/fractal;这是一个非常通用的转换工具。对于更简单的查询结果转换,也可以考虑使用quibble/transformer。
例如,在我们的用户示例中,表可能还包含一个我们不想公开的pass列。或者我们可以用它将用户ID转换为实际的整数,而不是字符串。
添加自定义方法
假设我们还需要为API添加端点来计算集合中项目总数的API端点(例如,用于分页)。这可以通过使用注解来实现
<?php class MyHandler extends Crud { /** * @Method GET * @Url /count/ */ public function countIt() { return $this->jsonResponse(3); } }
要为具有资源的端点定义一个自定义方法,只需在方法中要求关联的参数并指定一个自定义URL
<?php class MyHandler extends Crud { /** * @Method PUT * @Url /custom/:id/ */ public function thisIsSomethingCustom($id) { // ... } }
在内部,Crud处理器的默认方法始终可用,使用指定的HTTP方法和URL。如果您需要以任何原因覆盖它们,也可以注解它们。`@Url`注解附加到您给`Api`构造函数提供的任何基本URL上。如果省略,则将使用该URL原样使用(例如,用于处理`HEAD`或`OPTIONS`)。
根据GET或POST参数处理分页等问题
在您的处理器中尽情发挥吧!您也可以在这里转换数据,例如,在存储之前对某些字段进行`json_encode`。这个场景下可能用到的有用包包括League/Fractal和Quibble/Transformer。
Monki这个名字是什么意思?
我是双语使用者,在荷兰语中,“API”发音就像“小猴子”这个词。所以这就是原因。