RESTFUL API with yii 1.1.x
TL;DR: use the components => urlManager => rules to use HTTP verbs and don’t
forget to
authenticate
the request. Check out on github my sample
project that provides
a simple RESTFUL API.
Yii 1.x is not the best framework to write RESTFUL APIs. Its main problem it the lack of good handling of HTTP verbs other than POST and GET. However, PUT and DELETE become essential when one want to write a proper API. Fortunately, it is easy enough to add the missing support to Yii.
First, write a proper route configuration. Edit protected/config/main file
and write something like this:
'components'=>array(
...
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
array('api/index', 'pattern'=> 'api/', 'verb' => 'GET'),
array('api/create', 'pattern'=> 'api/','verb' => 'POST'),
array('api/update', 'pattern'=> 'api/','verb' => 'PUT'),
array('api/delete', 'pattern'=> 'api/','verb' => 'DELETE'),
),
),
...
the last four lines of the rules will instruct Yii that GET/POST/PUT/DELETE
requests to BASEURL/api will be handled by the ApiController class within
the functions actionIndex, actionCreate, actionUpdate, actionDelete
respectively.
Then, it is necessary to write some basic code for handling the API calls. We
must at least 1) get the data and 2) authenticate the requests. Moreover, we
may also want to log calls and so on. We will do all this in the beforeAction
funcion of ApiController.
To get data from the request we must take into account the type of the request.
In the case of a GET, data will be into the $\_GET variable. The POST can be
either a form request either a raw data request (typically a JSON one). In the
first case its data will be in the $\_POST variable, while in the second case
we must fetch data from PHP raw input stream which can be accessed via
php://input. The PUT and the DELETE only have raw input.
In order to get data from raw input stream, we can write a very simple data function like:
private function getContent()
{
if (null === $this->content)
{
if (0 === strlen(($this->content = file_get_contents('php://input'))))
{
$this->content = false;
}
}
return $this->content;
}
Next, we can use such a function to get data according to the request type:
switch($_SERVER['REQUEST_METHOD']) {
case 'GET':
$this->data = $_GET;
break;
case 'POST':
$this->data = CJSON::decode($this->getContent());
break;
case 'DELETE':
$this->data = CJSON::decode($this->getContent());
break;
case 'PUT':
$this->data = CJSON::decode($this->getContent());
break;
default:
// raise some error here
break;
}
Here, I talk about authentication.