web-love / wp-router

A Worpress REST api router inspired from ExpressJs.
MIT License
8 stars 2 forks source link

Allowing (optional) regex patterns in endpoints #1

Open nikrowell opened 4 years ago

nikrowell commented 4 years ago

Hi @sudomaxime 👋🏻

I like what you're doing with wp-router! I have a similar Express-inspired router with my Cranium proof-of-concept, but I think it was a little too abstracted (and have never actually used it 😆).

Experimenting with wp-router, one feature in Cranium that I think would be useful here is allowing both simplified endpoints and more complex / regex endpoints. Examples:

// simplified - allow all formats for the id param
$router->get('/meme/@id', function($req, $res) { 
    $page = get_page_by_path($slug);
    return $page; 
});

// optional params
$router->get('/blog(/@year(/@month(/@day)))', function($req, $res) {
    return [$req->get_param('year'), $req->get_param('month'), $req->get_param('day')];
});

// more specific - only alphanumeric, dashes etc
$router->get('/page/@slug:[a-zA-Z0-9-]+', function($req, $res) { 
    $page = get_page_by_path($slug);
    return $page; 
});

// more specific - only numeric params
$router->get('/users/edit/@id:[0-9]+', function($req, $res) { 
    return $req['id']; 
});

// even more specific 
$router->get('/entries/report.@format:xml|csv|json', function($req, $res) { 
    return 'Here is your report as a '.$req->get_param('format').' file!';
});

I realize this specific format (@ vs :) would be a breaking change, but curious if this is something you'd be interesting in supporting?

sudomaxime commented 4 years ago

I really like the idea, thanks for the interest !

We wanted to add different "match" support for the router as Wordpress can match on multiple things (slugs and ids).

My only concern is to find a syntax that is easy to use/explain and is ideomatic to the best REST api's standards. I guess we can look into the expressjs route definition syntax and find a common ground that can work with wordpress. The regular pattern matching of wordpress is hard to read and understand.

I will create a branch and try a few things over the weekend !

Let me know if you have other use-cases for pattern matching.

nikrowell commented 4 years ago

The above examples could be achieved by changing route_params_to_route_regex to:

private function route_params_to_route_regex (string $endpoint): string {
    $pattern = '#@([\w]+)(:([^/\(\)]*))?#';

    $regex = preg_replace_callback($pattern, function($matches) {
        return (isset($matches[3])) 
            ? '(?P<'.$matches[1].'>'.$matches[3].')' 
            : '(?P<'.$matches[1].'>[^/\?]+)';
    }, str_replace(')', ')?', $endpoint));

    return $regex;
}

... where $pattern could also be an overridable option on the Router constructor. This is similar to Express, although they use :param and :param(...) vs @param, and gives you the option to use the simplified version or introduce regex for more control.

Curious to hear what other ideas you have!