Respect/Rest

route for query params

Closed this issue · 11 comments

bazo commented

hi,

i need a route that would match the following url

http://example.com/api/users?email=bazo&another=value&...

i tried

$r3->get('/api/users?*', function() use($users) {
return $users->query($query);
});

then i tried escaping the ? with one \ and two \

neither worked

it always matches the next route
$r3->get('/api/users/*', $users);

how can i write a route for that?

you can try this:

$r3->get('/api/users/*/*/*', function($email,$other=null,$another=null) {
        /** list users where email, other or another */
});

https://github.com/Respect/Rest#using-parameters

bazo commented

i need only parameter, that would get as value the query string after ?, email=bazo&another=value&..

bazo commented

i think the problem is in the question mark, it somehow messes with the route

@bazo I did not understand, in my example you will have only the paramas.

bazo commented

no i will not. it won't match the request. the query string can be of arbitrary length

this matches the route, but the parameter is null, i would expect it to be ?email=bazo&another=value&...
$r3->get('/api/users/*', $clients);

@bazo whenever you need to define your routes! And you don't need the ?

You'll work like this;

$r3->get('/api/users/*/*/*', function($email,$other=null,$another=null) {
    // so you will receive your params
    $yourApp->dosomething($mail, $other, $another);
});
bazo commented

well, i need the ?
that's the whole point. the url is set. it can contain any number of query parameters.

There is a standard for describing patterns of any URI that could solve this quickly, the RFC 6570 which we discussed before but unfortunately I didn't have time to implement.

I've been using the router for a while and came up with some patterns, but they often involve other Respect components, althogh I'm sure it would be easy to find appropriate substitutions if needed.

Here is a rough sample for routing an endpoint with any valid query string mapping to SQL queries. I'm sure security and structure can be improved somehow, I'm just illustrating the concept!

use Respect\Relational\Sql as Query;
use Respect\Validation\Validator as v;

$router = new Respect\Rest\Router();
$db = new PDO(/* assuming a MySQL connection with a db containing a table users /*)
$mapper = new Respect\Relational\Mapper($db);

$router->get("/users", function() use ($mapper) {
   // Ensure GET is properly formatted
    v::each(
        v::string()->notEmpty()->length(1, 32), // rule for $_GET keys
        v::string()->notEmpty()->length(1, 32) // rule for $_GET values
    ))->assert($_GET);
    // If GET is OK return database data
    return $mapper->users($filter)->fetchAll(Query::limit(10));
});

// Encodes the return properly per mime-type
$router->always('Accept', array(
    'application/json' => 'json_encode',
    'text/html' => function ($data) {
        echo "Data: " . print_r($data, true);
    }
));

As you can see, the $_GET superglobal is used to handle query strings just like any PHP app. If you need to match a route only when specific aspects of the query string are available, depending on your case, it would be better to use the when routine. Let me show you:

$router->get('/users', function () {
    // this will match without query string
});

$router->get('/users', function() {
    // this will match when "username" is in query string. Otherwise the route above will catch. See "when" above:
})->when(function() {
    return array_key_exists('username', $_GET);
});

$router->get('/users', function() {
    // you can have more than one routes with when conditions, mind their order though
})->when(function() {
    return array_key_exists('another_strange_key', $_GET);
});

Hope that helps until we came up with a better solution for URI templates =)

He's alive! 😱

Hey @alganet great solution!

As always we aim to Respect php so you can use the skills you already have. =)