Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling RESTful url's PHP

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?

like image 761
user1121487 Avatar asked Dec 01 '12 00:12

user1121487


2 Answers

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.

like image 106
da5id Avatar answered Sep 24 '22 16:09

da5id


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>[^/]+)|/?$@" => 
            (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
like image 28
freedev Avatar answered Sep 25 '22 16:09

freedev