I’m having trouble grasping what would be the most proper way of handling RESTful url’s.
I’m having url’s like these:
http://localhost/products
http://localhost/products/123
http://localhost/products/123/color
Originally:
http://localhost/index.php?handler=products&productID=123&additional=color
As for now I’m using mod_rewrite:
RewriteRule ^([^/]*)([/])?([^/]*)?([/])?(.*)$ /index.php?handler=$1&productID=$3&additional=$5 [L,QSA]
And then I’m puzzling together the requests in index.php, something like:
if ($_GET['handler'] == 'products' && isset($_GET['productID'])) {
// get product by its id.
}
I’ve seen some creating a GET-query as one string like:
if ($_GET['handler'] == 'products/123/color')
Then, do you for example use regular expressions to get the values out of the query-string?
Is this a better approach to handle these url’s?
What are the pros and cons with these different approaches?
Is there some better way?
This .htaccess entry will send everything except existing files to index.php:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php
Then you can do something like this to convert the url into an array:
$url_array = explode('/', $_SERVER['REQUEST_URI']);
array_shift($url_array); // remove first value as it's empty
array_pop($url_array); // remove last value as it's empty
Then you can use a switch thusly:
switch ($url_array[0]) {
case 'products' :
// further products switch on url_array[1] if applicable
break;
case 'foo' :
// whatever
break;
default :
// home/login/etc
break;
}
That’s what I generally do anyway.
Answer:
You could use a different approach instead of match all parameters using apache rewrites you could match the full request path in PHP using preg_match.
Applying the PHP regular expression all the parameters will be moved into the $args
array.
$request_uri = @parse_url($_SERVER['REQUEST_URI']);
$path = $request_uri['path'];
$selectors = array(
"@^/products/(?P<productId>[^/]+)|/[email protected]" =>
(array( "GET" => "getProductById", "DELETE" => "deleteProductById" ))
);
foreach ($selectors as $regex => $funcs) {
if (preg_match($regex, $path, $args)) {
$method = $_SERVER['REQUEST_METHOD'];
if (isset($funcs[$method])) {
// here the request is handled and the correct method called.
echo "calling ".$funcs[$method]." for ".print_r($args);
$output = $funcs[$method]($args);
// handling the output...
}
break;
}
}
This approach has many benefits:
- You don’t have a rewrite for each REST service you’re developing. I like rewrites, but in this case you need a lot of freedom, and using rewrites you need to change Apache config every time you deploy/mantain a new service.
- You can have a single PHP frontend class for all incoming requests. The frontend dispatch all the requests to the correct controller.
- You can apply iteratively an array of regular expression to the incoming requests and then call the correct function or class controller/method accordingly to the successful match
- When finally the controller is instantiated to handle the request, here you can check the HTTP method used into http request