dongmei5168 2015-06-27 07:34
浏览 622

PHP - 将Api端点作为二叉树

My team is developing a R.E.S.T api for our platform.

some examples for endpoints we currently have:

  • campaigns/24566/pictures
  • campaigns/24566/users
  • users/23445646
  • users/campaigns

We currently writing the endpoints in an ugly way for checking the path and we're trying to build an abstract Endpoint class which will include the path to it and validate it.

Our goal is to create this abstract class in order to be able to easily add or remove endpoints just by adding or removing Endpoint classes.

Obviously, this structure of endpoints is screaming for binary tree structure but i'm having some troubles implementing it.

This is my pseudo logic:

  1. The request if for endpoint/sub_endpoint_1/sub_enpoint_5
  2. if there is a class named endpoint and if it can be route - create an instance.
  3. if endpoint has as child named sub_endpoint_1 - create an instance of it
  4. if sub_endpoint_1 has a child named sub_endpoint_5 - create an instance of it
  5. if this is a leaf - run the code in this endpoint

I was thinking about each end point should hold its parents and children but I'm troubles understand how can I first validate the whole path is correct.

If every endpoint can only knows what can before it and what can be after it i might end up with:

endpoint1/sub_endpoint_1/sub_endpoint_5

Would be great for some pseudo guide :)

  • 写回答

1条回答 默认 最新

  • doudou6050 2015-06-27 09:43
    关注

    I'm not sure if this is what you're asking for, but if I were you I'd use something well-tested and from a well-known framework. Even if you have customly coded PHP application, no frameworks used, you can install only the component(s) you need via composer.

    Let's take symfony/ruoting as an example. In order to take HTTP request context it will also require symfony/http-foundation. In order to install both, proceed to your project root directory, install composer if it's not yet installed and then

    composer require symfony/http-foundation composer require symfony/routing

    then you need to include vendor/autoload.php in your project entry point and that's it, you can use symfony/routing now. The good thing is that since symfony2 is a component framework, you don't need to install all the framework, just those two packages.

    Now if you create a test file with the following code:

    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);
    

    and try to open it, you will see something like:

    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"
    }
    

    If you then integrate it into your REST API entry script, you can pass $_SERVER['REQUEST_URI'] into ::match() method and then something like:

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

报告相同问题?

悬赏问题

  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值