Welcome Guest, Not a member yet? Register   Sign In
Working on a REST API, critique requested
#15

[eluser]Phil Sturgeon[/eluser]
How about this.

libraries/REST_controller.php

Code:
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class REST_Controller extends Controller {
    
    private $method;
    private $format;
    
    private $args;
    
    // List all supported methods, the first will be default
    private $supported_formats = array(
        'xml' => 'application/xml',
        'json' => 'application/json',
        'serialize' => 'text/plain',
        'php' => 'text/plain'
    );
    
    // Constructor function
    function __construct()
    {
        parent::Controller();
        
        $this->args = $this->uri->uri_to_assoc();
        
        $this->format = $this->_detect_format();
        $this->method = $this->_detect_method();
    }
    
    function _remap($object_called)
    {
        $controller_method = $object_called.'_'.$this->method;
        
        if($controller_method)
        {
            $this->$controller_method();
        }
    }
    
    // Main function to output data
    function response($data = '', $http_code = 200)
    {
        $this->output->set_status_header($http_code);
        
        // If the method exists, call it
        if(method_exists($this, '_'.$this->format))
        {
            // Set a XML header
            $this->output->set_header('Content-type: '.$this->supported_formats[$this->format]);
        
            $formatted_data = $this->{'_'.$this->format}($data);
            $this->output->set_output( $formatted_data );
        }
        
        else
        {
            $this->output->set_output( $data );
        }
    }

    
    // Detect which format should be used to output the data
    private function _detect_format()
    {
        if(array_key_exists('format', $this->args) && array_key_exists($this->args['format'], $this->supported_formats))
        {
            return $this->args['format'];
        }
        
        // If a HTTP_ACCEPT header is present...
        if($this->input->server('HTTP_ACCEPT'))
        {
            // Check to see if it matches a supported format
            foreach(array_keys($this->supported_formats) as $format)
            {
                if(strpos($this->input->server('HTTP_ACCEPT'), $format) !== FALSE)
                {
                    return $format;
                }
            }
        }
        
        // If it doesnt match any or no HTTP_ACCEPT header exists, uses the first (default) supported format
        list($default)=array_keys($this->supported_formats);
        return $default;
    }
    
    private function _detect_method()
    {
        $method = strtolower($this->input->server('REQUEST_METHOD'));
        if(in_array($method, array('get', 'delete', 'post', 'put')))
        {
            return $method;
        }

        return 'get';
    }
    
    
    // FORMATING FUNCTIONS ---------------------------------------------------------
    
    // Format XML for output
    private function _xml($data = array(), $structure = NULL, $basenode = 'xml')
    {
        // turn off compatibility mode as simple xml throws a wobbly if you don't.
        if (ini_get('zend.ze1_compatibility_mode') == 1)
        {
            ini_set ('zend.ze1_compatibility_mode', 0);
        }

        if ($structure == NULL)
        {
            $structure = simplexml_load_string("&lt;?xml version='1.0' encoding='utf-8'?&gt;<$basenode />");
        }

        // loop through the data passed in.
        foreach($data as $key => $value)
        {
            // no numeric keys in our xml please!
            if (is_numeric($key))
            {
                // make string key...
                //$key = "item_". (string) $key;
                $key = "item";
            }

            // replace anything not alpha numeric
            $key = preg_replace('/[^a-z0-9_-]/i', '', $key);

            // if there is another array found recrusively call this function
            if (is_array($value))
            {
                $node = $structure->addChild($key);
                // recrusive call.
                $this->_xml($value, $node, $basenode);
            }
            else
            {
                // add single node.

                $value = htmlentities($value, ENT_NOQUOTES, "UTF-8");

                $UsedKeys[] = $key;

                $structure->addChild($key, $value);
            }

        }
        
        // pass back as string. or simple xml object if you want!
        return $structure->asXML();
    }
    
    
    // Encode as JSON
    private function _json($data = array())
    {
        return json_encode($data);
    }
    
    // Encode as Serialized array
    private function _serialize($data = array())
    {
        return serialize($data);
    }
    
    // Encode raw PHP
    private function _php($data = array())
    {
        return var_export($data);
    }
}
?&gt;

Then you can call it in your api controller(s) like so:

controllers/api.php

Code:
&lt;?php

class Api extends REST_Controller {

    function something_get()
    {
        if($user = $this->some_model->get($this->args['id']))
        {
            $this->response($user, 200); // 200 being the HTTP response code
        }

        else
        {
            $this->response(NULL, 404);
        }
    }
    
    function something_delete()
    {
        $this->some_model->delete($this->args['id']);
        
        $this->response($user, 200); // 200 being the HTTP response code
    }
}

?&gt;

It supports xml, json, serialize and raw php output. The first two will be auto-detected (xml is defaulted if nothing more useful is detected) and latter of the formats require 'format/serialize' to be added to the URI.

This seems to work like a charm, and new formats can be added a piece of piss. This can also be used in a modular environment perfectly!

Feedback?


Messages In This Thread
Working on a REST API, critique requested - by El Forum - 05-29-2009, 08:13 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 09:15 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 09:25 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 09:30 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 09:35 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 09:37 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 09:39 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 09:43 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 09:48 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 09:55 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 10:03 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 10:31 AM
Working on a REST API, critique requested - by El Forum - 05-29-2009, 12:45 PM
Working on a REST API, critique requested - by El Forum - 06-03-2009, 03:53 AM
Working on a REST API, critique requested - by El Forum - 06-03-2009, 05:10 AM
Working on a REST API, critique requested - by El Forum - 06-03-2009, 05:29 AM
Working on a REST API, critique requested - by El Forum - 06-03-2009, 08:27 AM
Working on a REST API, critique requested - by El Forum - 06-03-2009, 08:28 AM
Working on a REST API, critique requested - by El Forum - 06-03-2009, 09:21 AM
Working on a REST API, critique requested - by El Forum - 06-03-2009, 09:26 AM
Working on a REST API, critique requested - by El Forum - 06-03-2009, 09:41 AM



Theme © iAndrew 2016 - Forum software by © MyBB