Summary of Good REST Api Design

Summary of points about good RESTful API design from below talk:

Definition: Representational state transfer (REST) or RESTful Web services are one way of providing interoperability between computer systems on the Internet. REST-compliant Web services allow requesting systems to access and manipulate textual representations of Web resources using a uniform and predefined set of stateless operations

1) 2 base urls
a) for collection (/dogs)
b) for a single element (/dogs/bo)
3) nouns are good, verbs are bad
4) Assocations GET /owners/bob/dogs
5) Complex Associations – Sweep under the carpet (behind the question mark)
6) pagination (offset, limit or start, count)
7) searching ( global: /search?q=fluffy+dog , scoped: /owners/bob/dogs/search?q=fluffy+dog)
8) versioning (as far to the left as possible)
9) give me exactly what i need

  • a) /people:(id,first_name,last_name)
  • b) ?fields=id,first_name,last_name

10) output format

  • a) /venue.json
  • b) ?output=json

11) Standardize Error Formats
12) Make dog to bark (/dog?event=bark)

Yii Built In functions – Generic

// For dropdown list
$list=CHtml::listData(SysState::model()->findAll(), 'state_id', 'state_name');
echo $form->dropDownList($model,'state_id', $list, array('empty'=>'Select state'));

// dynamic dropdown populate
Below lines create the country dropdown which updates state dropdown
'POST', //request type
'url' => Yii::app()->createUrl('manager/events/dynamicStates/'), //url to call.
//Style: ii::app()->createUrl('currentController/methodToCall')
'update' => '#Events_state_id', //selector to update
'data'=> array('country_code'=>'js:this.value')
//leave out the data key to pass all form values through
dropDownList($model,'country_code', $list['countries'], array('empty'=>'--none--', 'class'=>'form-control', 'ajax'=>$ajaxStatePopulate)) ?>
error( $model, 'country_code'); ?>

The above code updates the below line
dropDownList($model,'state_id', $list['states'], array('empty'=>'--none--', 'class'=>'form-control')) ?>
error( $model, 'state_id'); ?>

Called url will have the below code
$result = States::model->findAll();
$data = CHtml::listData($result,'id','name');
//return CHtml::listData($result, 'code', 'name');print_r($data);
echo CHtml::tag('option',
foreach($data as $value=>$name)
echo CHtml::tag('option',

// To update the of the value in text field
pre_reg_start_date = Common::formatDbDate($model->pre_reg_start_date)?>
textField( $model, 'pre_reg_start_date', array('class'=>'form-control selectDate')); ?>

// NEXT : update label
labelEx( $model, 'pre_reg_start_time', array('label'=>'Time') ); ?>

// NEXT : create link with id
$event_id))?>" class="btn btn-primary">Link

// NEXT : Set your messages in a controller:
Yii::app()->user->setFlash('success', "Data1 saved!");
Yii::app()->user->setFlash('error', "Data2 failed!");
Yii::app()->user->setFlash('notice', "Data3 ignored.");

Display them in your view:
user->getFlashes() as $key => $message) {
echo '

' . $message . "


// NEXT : Create url examples
$url=$this->createUrl($route,$params); // syntax

$url = Yii::app()->createUrl('site/index');

$url = Yii::app()->createUrl('site/index', array('id'=>100));

Create URL from Controller
Yii::app()->controller->createUrl("index", array("id"=>100));

create url withing same controller with id as parameter

Create absolute URL:
In order to create an absolute path url you need to use createAbsoluteUrl() function:

echo CHtml::link('text', array('site/index', 'id'=>100));

Redirection example


// Get base url

// get current url before ? mark

// Theme url

// get the theme name

// get base path

// home page url

// url related properties
Yii::app()->request->userHostAddress // IP address

// NEXT : rules example to validate the date and time
array('wave_date', 'type', 'type'=>'date', 'dateFormat'=>'MM/dd/yyyy'),
array('wave_time', 'type', 'type'=>'time', 'timeFormat'=>'hh:mm a'),

Text field

'form-control')); ?>

Text field using Form. It does same as above
textField( $model, 'name', array('class'=>'form-control')); ?>

Text field without form and model

Creating a simple widget
Step 1: components/BreadCrumb.php:

Step 2: components/views/breadCrumb.php

Step 3: Call from your actuall view as below
widget('application.components.BreadCrumb', array(
'crumbs' => array(
array('name' => 'Home', 'url' => array('site/index')),
array('name' => 'Login'),
'delimiter' => ' → ', // if you want to change it
)); ?>

// NEXT : Logging
Yii::log($message, $level, $category);
Yii::trace($message, $category);

// NEXT : end application
Yii::app()->end(); // does

// Set get session value
Yii::app()->session["lang"] = "English";
echo Yii::app()->session["lang"]

Yii DB built in functions – Reference

Quick reference – Yii inbuilt functions – DB related

###### Active Record functions: ############
Different ways to query
// 1st way
$criteria=new CDbCriteria;
$criteria->select=’title’; // only select the ‘title’ column

// 2nd way

//Other ways
// Find All
// find all rows satisfying the specified condition
// find all rows with the specified primary keys
// find all rows with the specified attribute values
// find all rows using the specified SQL statement

User::model()->findAll(‘first_name=? AND last_name=?’, array(‘Paul’, ‘Smith’));
User::model()->findAllByAttributes(array(‘first_name’=>’Paul’, ‘last_name’=>’Smith’));

// find one
$post=Post::model()->find(‘postID=:postID’, array(‘:postID’=>10));

// find by primary key

// find by attributes

// find by specified SQL statement

// count

// CREATE : creating record
$post=new Post;
$post->title=’sample post’;
$post->content=’content for the sample post’;
$post->create_time=time(); // $post->create_time=new CDbExpression(‘NOW()’);

// UPDATE: Updating Record
$post->title=’new post title’;
$post->save(); // save the change to database

// DELETE: Delete record
$post=Post::model()->findByPk(10); // assuming there is a post whose ID is 10

// Scopes
how to make use of scopes
In your model make a entry as below
// scope to get the 5 records of status=1 and recently updated
public function scopes()
return array(
‘order’=>’create_time DESC’,

And then use the below statement to query.

// write in model class to to some ops before saving
public function beforeSave() {
if ($this->isNewRecord)
$this->created = new CDbExpression(‘NOW()’);
$this->modified = new CDbExpression(‘NOW()’);
// anything else.. like, date modification, time modification, etc..

return parent::beforeSave();

######## Query builder functions: ############
// NEXT : sql command writing
$command = Yii::app()->db->createCommand(‘SELECT * FROM tbl_user’);

// fetch row
$user = Yii::app()->db->createCommand()
->select(‘id, username, profile’) // to fetch all use ->select(‘*’)
->from(‘tbl_user’) // for multiple table use as ->from(array(‘tbl_user’, ‘tbl_profile’))
->where(‘id=:id’, array(‘:id’=>$id))
$row = Yii::app()->db->createCommand(array(
‘select’ => array(‘id’, ‘username’),
‘from’ => ‘tbl_user’,
‘where’ => ‘id=:id’,
‘params’ => array(‘:id’=>1),

// Fetch row using join
$user = Yii::app()->db->createCommand()
->select(‘id, username, profile’)
->from(‘tbl_user u’)
->join(‘tbl_profile p’, ‘’) // join, leftJoin, rightJoin, crossJoin, naturalJoin
->where(‘id=:id’, array(‘:id’=>$id))

// fetch all
$user = Yii::app()->db->createCommand()
->select(‘id, username, profile’)
->where(‘id=:id’, array(‘:id’=>$id))
->limit(10, 20) // limit 10 and offset 20

$users = Yii::app()->db->createCommand()

// display SQL statement
$sql = Yii::app()->db->createCommand()

// build and execute the following SQL:
// INSERT INTO `tbl_user` (`name`, `email`) VALUES (:name, :email)
$command->insert(‘tbl_user’, array(

// UPDATE `tbl_user` SET `name`=:name WHERE id=:id
$command->update(‘tbl_user’, array(
), ‘id=:id’, array(‘:id’=>1));

// DELETE FROM `tbl_user` WHERE id=:id
$command->delete(‘tbl_user’, ‘id=:id’, array(‘:id’=>1));

// create a new entry with time modification example
$post=new Post;
$post->title = “Some title”;
$post->desciption = “Some description”;
$post->create_time=new CDbExpression(‘NOW()’);
// $post->create_time=’NOW()’; will not work because
// ‘NOW()’ will be treated as a string