PHP-将Api的端点作为二叉树


PHP - Rest Api end points as binary tree

我的团队正在为我们的平台开发R.E.S.T api。

我们目前拥有的端点的一些示例:

  • 活动/24566/图片
  • 活动/24566/用户
  • 用户/23345646
  • 用户/活动

我们目前以一种丑陋的方式编写端点来检查路径,我们正试图构建一个抽象的端点类,该类将包括它的路径并对其进行验证

我们的目标是创建这个抽象类,以便能够通过添加或删除Endpoint类来轻松添加或删除端点。

显然,这种端点结构要求二进制树结构,但我在实现它时遇到了一些麻烦

这是我的伪逻辑:

  1. 端点/sub_endpoint_1/sub_endpoint _5的请求
  2. 如果有一个名为endpoint的类,并且它可以是route,则创建一个实例
  3. 如果端点具有名为sub_endpoint1的子级-创建它的实例
  4. 如果sub_endpoint_1有一个名为sub_endpoint _5的子级-创建它的实例
  5. 如果这是一个叶子-在这个端点中运行代码

我在想每个终点都应该容纳它的父母和孩子,但我很难理解如何首先验证整个路径是正确的。

如果每个端点都只能知道在它之前和之后可以是什么,我可能会得到:

端点1/sub_endpoint_1/sub_endpoint_5

对于一些伪指南来说会很好:)

我不确定这是否是你想要的,但如果我是你,我会使用经过良好测试的、来自知名框架的东西。即使您已经习惯性地编写了PHP应用程序,并且没有使用任何框架,您也只能通过composer安装所需的组件。

让我们以symfony/ruoting为例。为了获取HTTP请求上下文,还需要symfony/http-foundation。为了安装两者,请转到您的项目根目录,如果尚未安装composer,请安装它,然后

composer需要symfony/http基础composer需要符号/路由

那么你需要在你的项目入口点中包括vendor/autoload.php,就这样,你现在可以使用symfony/routing了。好的是,由于symfony2是一个组件框架,您不需要安装所有的框架,只需要安装这两个包。

现在,如果您使用以下代码创建一个测试文件:

require_once(realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'));
use Symfony'Component'HttpFoundation'Request;
use Symfony'Component'Routing'Matcher'UrlMatcher;
use Symfony'Component'Routing'RequestContext;
use Symfony'Component'Routing'RouteCollection;
use Symfony'Component'Routing'Route;
$routes = new RouteCollection();
$route = new Route('/{endpoint}/{subendpoint}/{subsubendpoint}');
$route->setDefaults(array(
    'endpoint' => null,
    'subendpoint' => null,
    'subsubendpoint' => null,
));
$routes->add('main', $route);
$context = new RequestContext();
// this is optional and can be done without a Request instance
$context->fromRequest(Request::createFromGlobals());
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match('/hello');
var_dump($parameters);
$parameters = $matcher->match('/');
var_dump($parameters);
$parameters = $matcher->match('/campaigns/24566/pictures');
var_dump($parameters);
$parameters = $matcher->match('/campaigns/24566/users');
var_dump($parameters);
$parameters = $matcher->match('/users/23445646');
var_dump($parameters);
$parameters = $matcher->match('/users/campaigns');
var_dump($parameters);

试着打开它,你会看到这样的东西:

array(4) {
  ["endpoint"]=>
  string(5) "hello"
  ["subendpoint"]=>
  NULL
  ["subsubendpoint"]=>
  NULL
  ["_route"]=>
  string(4) "main"
}
array(4) {
  ["endpoint"]=>
  NULL
  ["subendpoint"]=>
  NULL
  ["subsubendpoint"]=>
  NULL
  ["_route"]=>
  string(4) "main"
}
array(4) {
  ["endpoint"]=>
  string(9) "campaigns"
  ["subendpoint"]=>
  string(5) "24566"
  ["subsubendpoint"]=>
  string(8) "pictures"
  ["_route"]=>
  string(4) "main"
}
array(4) {
  ["endpoint"]=>
  string(9) "campaigns"
  ["subendpoint"]=>
  string(5) "24566"
  ["subsubendpoint"]=>
  string(5) "users"
  ["_route"]=>
  string(4) "main"
}
array(4) {
  ["endpoint"]=>
  string(5) "users"
  ["subendpoint"]=>
  string(8) "23445646"
  ["subsubendpoint"]=>
  NULL
  ["_route"]=>
  string(4) "main"
}
array(4) {
  ["endpoint"]=>
  string(5) "users"
  ["subendpoint"]=>
  string(9) "campaigns"
  ["subsubendpoint"]=>
  NULL
  ["_route"]=>
  string(4) "main"
}

如果将其集成到REST API入口脚本中,则可以将$_SERVER['REQUEST_URI']传递到::match()方法中,然后传递类似以下内容:

if(!empty($parameters['subsubendpoint'])) {
    //instantiate the "leaf"-subclass
} elseif(!empty($parameters['subendpoint'])) {
    //instantiate the "middle"-subclass
} else {
    //instantiate the "main" class
}