Home » Php » Handling RESTful url's PHP

Handling RESTful url's PHP

Posted by: admin July 12, 2020 Leave a comment

Questions:

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?

How to&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.

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