Welcome Guest, Not a member yet? Register   Sign In
Controller Method file extensions? (.xml or .php)
#1

[eluser]Fenix[/eluser]
Hello,

I'm building a RESTful API and would like some advice on how to accomplish user-defined return types the following way:

When accessing a particular endpoint of the API (in this example, the "categories" endpoint) the user would be able to specify the return type by adding the desired file extension like this:

Code:
// For an XML response
'http://mysite.com/api/categories.xml?accesskey=555555555&orderby=id&sort=desc'

// For a serialized PHP response
'http://mysite.com/api/categories.php?accesskey=555555555&orderby=id&sort=desc'

// For a JSON object response
'http://mysite.com/api/categories.json?accesskey=555555555&orderby=id&sort=desc'

I have the query string part figured out, and I'd prefer to do the response type this way rather than having the it as an item in the query string.

So, it's not possible to have a method in my API controller be categories.xml() so how can this be done in a fairly simple way? I assume there is a dynamic URL routing method?
#2

[eluser]slowgary[/eluser]
You could use the _remap() method and break the URI up yourself. Something like this:
Code:
function _remap($method)
{
     switch(stristr($method, '?', true))  //check everything before the '?' char
     {
          case 'categories.xml':   xml(stristr($method, '?'));  //pass everything after the '?' char
                                   break;
          case 'categories.php':   php(stristr($method, '?'));  //pass everything after the '?' char
                                   break;
          case 'categories.json':  json(stristr($method, '?'));  //pass everything after the '?' char
                                   break;
     }
}

I haven't tested that so pardon me if you try it and it blows up the whole world. Also, this could be expensive, I'm not really sure.
#3

[eluser]xwero[/eluser]
I wonder why you need to mix segments with query strings they make it more difficult for the user to create the url.

I would allow users to create urls like these
Code:
// For an XML response
'http://mysite.com/api/categories/orderby/id/sort/desc.xml?accesskey=555555555'
'http://mysite.com/api/categories/.xml?accesskey=555555555'

// For a serialized PHP response
'http://mysite.com/api/categories/orderby/id/sort/desc.php?accesskey=555555555'

// For a JSON object response
'http://mysite.com/api/categories/orderby/id/sort/desc.json?accesskey=555555555'
I would only keep the accesskey in the querystring because it has nothing to do with the data itself.

So the controller method would look like this
Code:
function categories()
{
   $format = '.php'; // default output
   $valid_formats = array('.php','.xml','.json');

   $optional = $this->uri->uri_to_assoc(); // the default segment is 3 so this works on this url

   if(count($optional) == 1 && current($optional) == false && in_array(current(array_keys($optional)),$valid_formats))
   {
       $format = current(array_keys($optional));
       $optional = array();
   }
   elseif(count($optional) >= 1 && in_array(strrchr(end($optional),'.'),$valid_formats))
   {
      $format = strrchr(end($optional),'.');
      $optional[count($optional)-1] = str_replace($format,'',end($optional));
   }
   // build query with(out) optional limits
   // output the desired format
}
#4

[eluser]Fenix[/eluser]
On the contrary. I find it much easier to use the URLs the way I am doing it now:

Code:
// to get the CI part of the URI (/api/categories) I just do this:
$this->uri->uri_string()

// to grab the query string and put it into an associative array, I use
parse_str($_SERVER['QUERY_STRING'],$this->query_string);

// to check if all the required arguments were passed, I just check for the key in the array like this
if(array_key_exists('appkey',$this->query_string))

// see? no need for changing messy CI configurations at all! :)

I'm going to try the _remap() method as slowgary descibed above. I'll update with my results.

THanks so far!
#5

[eluser]xwero[/eluser]
wasn't the point to identify the format? I don't see it in your latest snippet.
#6

[eluser]slowgary[/eluser]
He means the user that will be making the api calls. I think the user will figure it out.
#7

[eluser]Fenix[/eluser]
I haven't tried the remap method yet, but this is what I have it doing now. If a user wants a response type other than the default of XML, they would pass an argument "response" with "php".

I only posted the last snippet because you said you thought query strings make it more difficult. I was showing the contrary.

Code:
if(array_key_exists('response',$this->query_string))
{
    switch($this->query_string['response'])
    {
        case 'php': $this->content_type = 'php'; break;
        case 'xml': $this->content_type = 'xml'; break;
        default: $this->errors[] = 1003;
    }
}
else
{
    // no response type explicitly requested, use default
    $this->content_type = $this->default_content_type;
}
#8

[eluser]xwero[/eluser]
[quote author="Fenix" date="1240599325"]I only posted the last snippet because you said you thought query strings make it more difficult. I was showing the contrary.[/quote]
Query strings make it difficult for the user to build their custom data request. Isn't
http://mysite.com/api/categories/orderby...=555555555
easier to understand than
http://mysite.com/api/categories.xml?acc...&sort=desc

Functionalities should always be developed thinking about the users first. For example quite a few people don't like it the database api uses so many methods to build a sql statement. I think they rather saw only three methods for the select statement: rows, row and value. And these statement have all the parameters to build any kind of sql statement.

The same goes for building urls. You have a part as segments and a part as a query string separated by the accesskey.

of course it's up to you if you want to make it easy on yourself or on your site/app users.
#9

[eluser]Fenix[/eluser]
I'm working with the _remap() method recommended by slowgary above, it's working great for the xml type but when I get to the php type, CI is assuming I'm looking for a php file and gives me a 404 Not Found error. Any way I can get around this?

Here is what I have so far. It doesn't actually remap anything but it gets the content type for the response at least for xml.

Code:
function _remap($method)
{
    $content_type = stristr($method, '.');
    switch($content_type)
    {
        case '.php': $this->content_type = 'php'; break;
        case '.xml': $this->content_type = 'xml'; break;
        default: $this->errors[] = 1003;
    }
}
#10

[eluser]Fenix[/eluser]
[quote author="xwero" date="1240601162"]
Query strings make it difficult for the user to build their custom data request. Isn't
http://mysite.com/api/categories/orderby...=555555555
easier to understand than
http://mysite.com/api/categories.xml?acc...&sort=desc
[/quote]

I think you are contradicting yourself with this one. URLs are hierarchical. It is much easier for the user to see the key-value pairs in the query string. It also eliminates confusion when you get into required vs optional parameters. I also believe you lose site of the actual endpoint you are trying to access if you use your method.

I am not completely abandoning your method however. There are circumstances when appropriate data will be passed before the query string. Example:
api/user/{user name}/items?from_date=123456&to_date=123556&sort=desc

Moreover, this is how many, if not most, REST APIs work.
Digg API
Last.fm API
Flickr API




Theme © iAndrew 2016 - Forum software by © MyBB