Adapting a existing API using routing ?

#1
[eluser]Mario Z.[/eluser]
Hi all,
First, my congratulations for this good and neat framework !
I have been testing it for a while, and I am beginning a new project with it.

But I am stucked with the (recurring) URI routing problem.
I have read some previous threads about this, and about why the segmented URLs are best, and not using query strings, etc.

But the problem is I have an existing and defined API, which has been used in a lot of Javascript code, and what I want is to reimplement it using CodeIgniter, without changing the REST API. Not too crazy, ok ? That's the way things should be done, change the implementation, without changing the interface. Old OO practice.
It has been in good use for a long time, has a good REST design, etc. So changing it is not possible.
The API uses a lot of query strings and segmented URLS too, Something like document/id=1234/body?as=pdf&draft=yes&sign=xxxx

I tried developing a router, which will receive the request, transform it into a valid CodeIgniter route, and then call the corresponding controller-method.

I extracted some code from the Router.php, and created a standard draft RestRouter.php script to act as a front end to CodeIgniter (the code is below).

My problem is I can´t imagine how to call the CodeIgniter controller from this script.

Using redirect (changing the http location header) seems like a bad solution (it will go back to the browser and then again to the server).
And I don't want to touch the CodeIgniter core (I know some routing solutions do this).
I will rather use an external Adapter without messing with the CodeIgniter core.

Can somebody help me here ? :-S
Thanks in advance !!!

The draft RestRouter.php code
=============================
Code:
// Configure the Router mappings here
$routes['GET']["/sem/rest.php/document/id=(:any)/preview?as=(:any)&draft;=(:any)&sign;=(:any)"]
       ="/sem/newApi.php/document/preview/$1/$2/$3/$4";

// URL processing here
$url = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
if (($method == "POST") && ($_POST['_method']=="PUT")) { $method = "PUT"; }
if (($method == "POST") && ($_POST['_method']=="DELETE")) { $method = "PUT"; }
$redirect=router($routes[$method], $url) ;
echo "<h3>url:$url</h3>";
echo "<h3>Redirect:$redirect</h3>";
//http_redirect($redirect); ???

// Convert the URL
// this has been taken from Router.php
function router($routes, $uri) {
    // Loop through the route array looking for wild-cards
    foreach ($routes as $key => $val)
    {
            // Convert wild-cards to RegEx
            $key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key));
            // To support QUERY_STRING, we must escape '&' and '?'
            $key = str_replace('?', '\?', str_replace('&', '\&', $key));
            echo "<br/>uri:$uri<br/>key:$key";

            // Does the RegEx match?
            if (preg_match('#^'.$key.'$#', $uri))
            {
                    // Do we have a back-reference?
                    if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
                    {
                            $val = preg_replace('#^'.$key.'$#', $val, $uri);
                    }
                    return $val;
            }
    }
}

#2
[eluser]Phil Sturgeon[/eluser]
I'd recommend taking a look at my REST server code (link in my sig) and using .htaccess rules to rewrite the old calls. I'm doing this exact same thing at work right now and its working perfectly.

#3
[eluser]Mario Z.[/eluser]
Phil, thanks for the reply.
I looked at your REST server, it seems to be a very nice piece of code and I completely agree with you in the assumptions. REST is not a library !
I have two questions:
1-Can we use query strings AND URL segments together ?
Such as in
Quote:document/myid/properties?fmt=json&sign=xxxx&datefmt=dd-mm-yyyy&numfmt=coma&lang=ca
I couldn't find an example using them in your docs.
2-Using .htaccess is not (always) an option since sometimes we install our software in other web servers (IIS), not only Apache.
So I would prefer to do all the routing magic inside PHP.
Thanks again :-)
Mario

#4
[eluser]Phil Sturgeon[/eluser]
1.) This is as close to default CI behaviour as possible, so you will need to enable query strings and uri segments the same as usual. They should both be accessible via $this->get() then, ?=something/val2 will override /something/val1 though so watch out.

2.) I figured this would be a "one-api - one server" sort of thing. Just use Routes if you are up to it.

#5
[eluser]Mario Z.[/eluser]
Phil, thanks for answering so fast !

Quote:1.) This is as close to default CI behaviour as possible, so you will need to enable query strings and uri segments the same as usual. They should both be accessible via $this->get() then, ?=something/val2 will override /something/val1 though so watch out.
I have tried to do this before, but failed for some reason.
I will use the options you mention in the thread.
I was using QUERY_STRING instead of PATH_INFO, so maybe that was the error.
I will give it a try.

Quote:2.) I figured this would be a “one-api - one server” sort of thing. Just use Routes if you are up to it.
Yes, if I can have both URI segs and query strings, maybe the std routing will be enough.

Thanks again!

#6
[eluser]Mario Z.[/eluser]
Quote:1.) This is as close to default CI behaviour as possible, so you will need to enable query strings and uri segments the same as usual. They should both be accessible via $this->get() then, ?=something/val2 will override /something/val1 though so watch out.

I have tried to do this before, but failed for some reason.
I will use the options you mention in the thread.
I was using QUERY_STRING instead of PATH_INFO, so maybe that was the error.
I will give it a try.
Good ! This is working ! PATH_INFO must be used in the uri_protocol option.
So one of the problems is solved, and now I can use your REST server :-)

Btw: you also have to add ?&= to the allowed chars:

Code:
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_(),\-\=\?\&';

Quote:2.) I figured this would be a “one-api - one server” sort of thing. Just use Routes if you are up to it.

Yes, if I can have both URI segs and query strings, maybe the std routing will be enough.
BUT the routing still gives me troubles :-(

Just for an example:
I have a Search controller, and a getResults() method.
The route is configured as:

Code:
$route["search/rs?(:any)"]="search/getResults?$1";

If I type: http://apps/sem/api.php/search/getResults?q1=a&q2=b
This works Ok, and the get params are in the GET array, etc ...

But if I type: http://apps/sem/api.php/search/rs?q1=a&q2=b
I get the 404 error.

I also tried to change the route to:
Code:
$route["search/rs\?(:any)"]="search/getResults?$1";
Without success.

#7
[eluser]Phil Sturgeon[/eluser]
I dont think you can use query strings in the routing. Just match up the URI segments and use the same $_GET variables accessed via $this->get();

Also, I updated the REST server on GitHub today to allow var $rest_format to be added to the property declaration of your REST controllers. This means instead of defaulting to XML, that controller can default to any format you set.

E.g:

Code:
&lt;?php

require(APPPATH.'/libraries/REST_Controller.php');

class Personal_data extends REST_Controller
{
    var $rest_format = 'serialize';


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


Users browsing this thread:
1 Guest(s)


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2019 MyBB Group.