DEV Community

Rahimie Ahmad
Rahimie Ahmad

Posted on

Exedra - Nested Routing PHP microframework

Introduction

A PHP microframework with focus to do nested/grouped routing while being able to attach a middleware contextually. Nest level is infinite.

Imagine having uris like :

GET    /apis/users
POST   /apis/users
GET    /apis/users/:user-id
PATCH  /apis/users/:user-id
GET    /apis/users/:user-id/friends
DELETE /apis/users/:user-id/friends/:friend-id

In this case you would do something like

use Exedra\Routing\Group;
use Exedra\Runtime\Context;

require_once __DIR__ .'/vendor/autoload.php';

$app = new \Exedra\Application(__DIR__);

$app->map['apis']->any('/apis')->group(function(Group $apis) {
  $apis['users']->any('/users')->group(function(Group $users) {
    $users['list']->get('/')->execute(function(Context $context){});
    $users['add']->post('/')->execute(function(){});
    $users['user']->any('/:user-id')->group(function(Group $user) {
      $user['get']->get('/')->execute(function(){});
        $user['update']->patch('/')->execute(function(){});
        $user['friends']->group(function(Group $friends) {
          $friends['list']->get('/')->execute(function(){});
          $friends['delete']->delete('/:friend-id')->execute(function(){});
        });
      });
  });
});

And running a symfony console command will give you something like

Showing list of routes :
+--------------------------------+--------+-----+---------------------------------+
| name                           | method | tag | uri                             |
+--------------------------------+--------+-----+---------------------------------+
| apis.users.list                | get    |     | /apis/users                     |
| apis.users.add                 | post   |     | /apis/users                     |
| apis.users.user.get            | get    |     | /apis/users/:user-id            |
| apis.users.user.update         | patch  |     | /apis/users/:user-id            |
| apis.users.user.friends.list   | get    |     | /apis/users/:user-id            |
| apis.users.user.friends.delete | delete |     | /apis/users/:user-id/:friend-id |
+--------------------------------+--------+-----+---------------------------------+

The raw sample might look complicated as it goes deeper. In this case you might want to use a class based routing controller as the group pattern. Related docs

Documentation

Head over to http://exedra.rosengate.com or http://github.com/rosengate/exedra-web if the site is dead one day

Why another framework

I just need a router that can do a very nested routing. So, I wrote one back in 2016, yet haven't really released as 1.0.0 (now at 0.9.4) and never really to public. Been using in number of personal projects before, but it's been 4 years, I think I just wanna be done and complete it for good. Since it's a microframework, it wouldn't need much components as there're tons of other great packages out there, not mentioning Symfony packages.

The basic component it has currently is php session, annotation based routing controller, path, url factory and some other things I might have forgot.

Why nested routing

Separating concerns primarily. Imagine having 200 routes for your app, and everything happened in a flat registry, maintaining them would be quite a nightmare. Another thing about having a dedicated group of routing is, that you can attach some sort of middleware (or authentication layer) for a group anonymously.

And secondly, a lot of framework/microframeworks out there maps their route to action/controller explicitly, and to me managing both routing and controller/actions class separately introduces cognitive burden as the routing grows bigger. So I build a annotation based routing controller dedicated to handle both routing and action in the same place.

Thank you

I am planning to release it as 1.0.0 once and for all once I've done some unit tests on routing controller later.

Any feedback is welcome. Thank you.

Top comments (0)