Difference between #11 and #12 of
How-To: Create a REST API

Revision #12 has been created by Maurizio Domba Cerin on Apr 16, 2011, 7:18:34 AM with the memo:

formated code indent
« previous (#11) next (#13) »

Changes

Title unchanged

How-To: Create a REST API

Category unchanged

How-tos

Yii version unchanged

Tags unchanged

REST, API, Tutorial

Content changed

[...]
In order to parse these URL's, set up the URL manager in _config/main.php_ like this:


```php
...
        'urlManager'=>array(      'urlFormat'=>'path',      'rules'=>array(                  'post/<id:\d+>/<title:.*?>'=>'post/view',                  'posts/<tag:.*?>'=>'post/index',                  // REST patterns                  array('api/list', 'pattern'=>'api/<model:\w+>', 'verb'=>'GET'),                  array('api/view', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'GET'),                  array('api/update', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'PUT'),  // Update
 
                

 
array('api/delete', 'pattern'=>'api/<model:\w+>/<id:\d+>', 'verb'=>'DELETE'),                  array('api/create', 'pattern'=>'api/<model:\w+>', 'verb'=>'POST'), // Create
 
                

 
// Other controllers                  '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',      ),
 
        ),
 
        
),
 
),
 
...
```
[...]
```php
class
 
class ApiController extends Controller
{
// Members
[...]
return array();
}

 
// Actions
 
public function actionList() { }
 
public function actionView() { }
 
public function actionCreate() { }
 
public function actionUpdate() { }
 
public function actionDelete()
{
}
[...]
```php
public function actionList()
    {
 
    
{
 
// Get the respective model instance      switch($_GET['model'])     {
 
    
{
 
case 'posts':      $models = Post::model()->findAll();     break;     default:      // Model not implemented error     $this->_sendResponse(501, sprintf(
 
                
'Error: Mode <b>list</b> is not implemented for model <b>%s</b>',
 
                
$_GET['model']) );     exit;      }      // Did we get some results?     if(is_null($models)) {     // No     $this->_sendResponse(200,
 
                
sprintf('No items where found for model <b>%s</b>', $_GET['model']) );      } else {      // Prepare response     $rows = array();      foreach($models as $model)     $rows[] = $model->attributes;     // Send the response      $this->_sendResponse(200, CJSON::encode($rows));     }
 
    } // }}} 
}
 
}

```
[...]
```php
public function actionView()
    {      // Check if id was submitted via GET      if(!isset($_GET['id']))     $this->_sendResponse(500, 'Error: Parameter <b>id</b> is missing' );      switch($_GET['model'])     {      // Find respective model     case 'posts':     $model = Post::model()->findByPk($_GET['id']);     break;     default:      $this->_sendResponse(501, sprintf(
 
                
'Mode <b>view</b> is not implemented for model <b>%s</b>',
 
                
$_GET['model']) );     exit; // }}} 
 
    

 
}      // Did we find the requested model?
 
    
 If not, raise an error
 
if(is_null($model)) {             // No, raise an error 
 
    
$this->_sendResponse(404, 'No Item found with id '.$_GET['id']);     } else {
 
            
 
    
else
 
$this->_sendResponse(200, CJSON::encode($_GET['model']));         }
 
    } // }}} 
}
```
[...]
```php
public function actionCreate()
    {
 
    
{
 
switch($_GET['model'])     {
 
    
{
 
// Get an instance of the respective model     case 'posts':      $model = new Post;     break;     default:     $this->_sendResponse(501,
 
                
sprintf('Mode <b>create</b> is not implemented for model <b>%s</b>',
 
                
$_GET['model']) ); exit;     }
 
    
}
 
// Try to assign POST values to attributes     foreach($_POST as $var=>$value) {      // Does the model have this attribute?
 
    
 If not raise an error
 
if($model->hasAttribute($var)) {     $model->$var = $value;      } else {                 // No, raise an error
 
    
$this->_sendResponse(500,
 
                
sprintf('Parameter <b>%s</b> is not allowed for model <b>%s</b>', $var,
 
               
$_GET['model']) );         }
 
        }
 
    
}
 
// Try to save the model     if($model->save()) {
 
            // Saving was OK
 
    

 
$this->_sendResponse(200,
 
                
$this->_getObjectEncoded($_GET['model'], $model->attributes) );     } else {      // Errors occurred     $msg = "<h1>Error</h1>";      $msg .= sprintf("Couldn't create model <b>%s</b>", $_GET['model']);     $msg .= "<ul>";      foreach($model->errors as $attribute=>$attr_errors) {     $msg .= "<li>Attribute: $attribute</li>";     $msg .= "<ul>";      foreach($attr_errors as $attr_error) {     $msg .= "<li>$attr_error</li>";                 }        
 
    
$msg .= "</ul>";      }     $msg .= "</ul>";      $this->_sendResponse(500, $msg );     }
 
    } // }}
}
 
}
```
[...]
```php
public function actionUpdate()
    {
 
{      // Parse the PUT parameters      parse_str(file_get_contents('php://input'), $put_vars);     switch($_GET['model'])     {
 
    
{
 
// Find respective model     case 'posts':      $model = Post::model()->findByPk($_GET['id']);     break;     default:      $this->_sendResponse(501,
 
                
sprintf( 'Error: Mode <b>update</b> is not implemented for model <b>%s</b>',
 
                
$_GET['model']) );     exit;     }     // Did we find the requested model?
 
    
 If not, raise an error
 
if(is_null($model)) {             // No, raise an error
 
    
$this->_sendResponse(400,
 
                
sprintf("Error: Didn't find any model <b>%s</b> with ID <b>%s</b>.",
 
                
$_GET['model'], $_GET['id']) ); }         
 
    
// Try to assign PUT parameters to attributes      foreach($put_vars as $var=>$value) {     // Does model have this attribute?
 
    
 If not, raise an error
 
if($model->hasAttribute($var)) {
 
   

 
 $model->$var = $value;      } else {                 // No, raise error
 
    
$this->_sendResponse(500,
 
                
sprintf('Parameter <b>%s</b> is not allowed for model <b>%s</b>',
 
               
$var, $_GET['model']) );     }     }
 
    
}
 
// Try to save the model     if($model->save()) {
 
    

 
$this->_sendResponse(200,
 
                
sprintf('The model <b>%s</b> with id <b>%s</b> has been updated.',
 
               
$_GET['model'], $_GET['id']) );     } else {
 
    
else
 
// prepare the error $msg     // see actionCreate      // ...     $this->_sendResponse(500, $msg );         }
 
    
}
```
[...]
```php
public function actionDelete()
    {
 
    
{
 
switch($_GET['model'])      {     // Load the respective model     case 'posts':      $model = Post::model()->findByPk($_GET['id']);     break;      default:     $this->_sendResponse(501,
 
                
sprintf('Error: Mode <b>delete</b> is not implemented for model <b>%s</b>',
 
                
$_GET['model']) );     exit;     }     // Was a model found?
 
        if(is_null($model)) {
 
            // No, raise an error
 
    
 If not, raise an error
 
    if(is_null($model))
 
$this->_sendResponse(400,
 
                
sprintf("Error: Didn't find any model <b>%s</b> with ID <b>%s</b>.",
 
                
$_GET['model'], $_GET['id']) );         }
 
 
  

 
  // Delete the model     $num = $model->delete();      if($num>0)     $this->_sendResponse(200,
 
                
sprintf("Model <b>%s</b> with ID <b>%s</b> has been deleted.",
 
                
$_GET['model'], $_GET['id']) );      else      $this->_sendResponse(500,
 
                
sprintf("Error: Couldn't delete model <b>%s</b> with ID <b>%s</b>.",
 
                
$_GET['model'], $_GET['id']) );     }
```
[...]
```php
private function _sendResponse($status = 200, $body = '', $content_type = 'text/html')
{
 
{
 
    
// set the status
 
$status_header = 'HTTP/1.1 ' . $status . ' ' . $this->_getStatusCodeMessage($status);         // set the status
 
    
header($status_header);     // setand the content type     header('Content-type: ' . $content_type);      // pages with body are easy     if($body != '')     {
 
    
{
 
// send the body     echo $body;     exit;     }      // we need to create the body if none is passed     else      {      // create some body messages     $message = '';      // this is purely optional, but makes the pages a little nicer to read     // for your users. Since you won't likely send a lot of different status codes,     // this also shouldn't be too ponderous to maintain      switch($status)     {
 
    
{
 
case 401:     $message = 'You must be authorized to view this page.';     break;      case 404:     $message = 'The requested URL ' . $_SERVER['REQUEST_URI'] . ' was not found.';     break;     case 500:      $message = 'The server encountered an error processing your request.';     break;      case 501:      $message = 'The requested method is not implemented.';     break;     }      // servers don't always have a signature turned on
 
        // 
(this is an apache directive "ServerSignature On")      $signature = ($_SERVER['SERVER_SIGNATURE'] == '') ? $_SERVER['SERVER_SOFTWARE'] . ' Server at ' . $_SERVER['SERVER_NAME'] . ' Port ' . $_SERVER['SERVER_PORT'] : $_SERVER['SERVER_SIGNATURE'];     // this should be templated in a real-world solution     $body = '
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">                         <html>
 
                            <head>
 
                            
<html>
 
<head>
 
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">                              <title>' . $status . ' ' . $this->_getStatusCodeMessage($status) . '</title>                             </head>
 
                            <body>
 
                            
</head>
 
<body>
 
<h1>' . $this->_getStatusCodeMessage($status) . '</h1>                              <p>' . $message . '</p>                             <hr />
 
                                <address>' . $signature . '</address>
 
                            </body>
 
                        
<hr />
 
    <address>' . $signature . '</address>
 
</body>
 
</html>';     echo $body;     exit;      }     } // }}}            }
```
[...]
```php
private function _getStatusCodeMessage($status)
    {
 
    
{
 
// these could be stored in a .ini file and loaded     // via parse_ini_file()... however, this will suffice      // for an example     $codes = Array(     200 => 'OK',      400 => 'Bad Request',     401 => 'Unauthorized',      402 => 'Payment Required',      403 => 'Forbidden',     404 => 'Not Found',      500 => 'Internal Server Error',     501 => 'Not Implemented',      );     return (isset($codes[$status])) ? $codes[$status] : '';     } // }}} 
 
}
```
[...]
```php
private function _checkAuth()
    {      // Check if we have the USERNAME and PASSWORD HTTP headers set?      if(!(isset($_SERVER['HTTP_X_USERNAME']) and isset($_SERVER['HTTP_X_PASSWORD']))) {     // Error: Unauthorized      $this->_sendResponse(401);     }      $username = $_SERVER['HTTP_X_USERNAME'];      $password = $_SERVER['HTTP_X_PASSWORD'];     // Find the user      $user=User::model()->find('LOWER(username)=?',array(strtolower($username)));     if($user===null) {      // Error: Unauthorized      $this->_sendResponse(401, 'Error: User Name is invalid');      } else if(!$user->validatePassword($password)) {     // Error: Unauthorized     $this->_sendResponse(401, 'Error: User Password is invalid');     }
 
    } // }}} 
}
 
}

```

Also, in all REST methods where an authentication is required, we need to put
[...]
98 2
123 followers
Viewed: 498 374 times
Version: 1.1
Category: How-tos
Written by: jwerner
Last updated by: Rohit Suthar
Created on: Apr 15, 2011
Last updated: 9 years ago
Update Article

Revisions

View all history