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

https://blog.apigee.com/detail/restful_api_design

1) 2 base urls
a) for collection (/dogs)
b) for a single element (/dogs/bo)
2) POST, GET, PUT, DELETE
3) nouns are good, verbs are bad
4) Assocations GET /owners/bob/dogs
5) Complex Associations – Sweep under the carpet (behind the question mark)
(/dogs?state=barking&color=red)
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',
array('value'=>''),CHtml::encode('--none--'),true);
foreach($data as $value=>$name)
{
echo CHtml::tag('option',
array('value'=>$value),CHtml::encode($name),true);
}

// NEXT
// 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 . "

\n";
}
?>

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

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

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

Create URL from Controller
Yii::app()->controller->createUrl("index", array("id"=>100));
index.php?r=site/index&id=100

create url withing same controller with id as parameter
$this->createUrl('index',array('id'=>100));

Create absolute URL:
In order to create an absolute path url you need to use createAbsoluteUrl() function:
Yii::app()->createAbsoluteUrl('site/index',array('id'=>100));
http://yourdomain.com/index.php?r=site/index&id=100

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

Redirection example
$this->redirect(array('site/index','id'=>100));
index.php?r=site/index&id=100

$this->redirect(array('site/index','id'=>100));

// Get base url
Yii::app()->baseUrl

// get current url before ? mark
Yii::app()->request->pathInfo

// Theme url
Yii::app()->theme->baseUrl

// get the theme name
Yii::app()->theme->name

// get base path
$this->getBasePath()

// home page url
$this->getHomeUrl()

// url related properties
Yii::app()->request->pathInfo
Yii::app()->request->url
Yii::app()->request->requestUri
Yii::app()->request->queryString
Yii::app()->request->isSecureConnection
Yii::app()->request->isPostRequest
Yii::app()->request->isAjaxRequest
Yii::app()->request->serverName
Yii::app()->request->urlReferrer
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

Example:
'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:
render('breadCrumb');
}

}
?>
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
$criteria->condition=’postID=:postID’;
$criteria->params=array(‘:postID’=>10);
$post=Post::model()->find($criteria);

// 2nd way
$post=Post::model()->find(array(
‘select’=>’title’,
‘condition’=>’postID=:postID’,
‘params’=>array(‘:postID’=>10),
));

//Other ways
// Find All
// find all rows satisfying the specified condition
$posts=Post::model()->findAll($condition,$params);
// find all rows with the specified primary keys
$posts=Post::model()->findAllByPk($postIDs,$condition,$params);
// find all rows with the specified attribute values
$posts=Post::model()->findAllByAttributes($attributes,$condition,$params);
// find all rows using the specified SQL statement
$posts=Post::model()->findAllBySql($sql,$params);

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($condition,$params);
$post=Post::model()->find(‘postID=:postID’, array(‘:postID’=>10));

// find by primary key
$post=Post::model()->findByPk($postID,$condition,$params);

// find by attributes
$post=Post::model()->findByAttributes($attributes,$condition,$params);
$post=Post::model()->findByAttributes();

// find by specified SQL statement
$post=Post::model()->findBySql($sql,$params);

// count
$n=Post::model()->count($condition,$params);

// 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()’);
$post->save();

// UPDATE: Updating Record
$post=Post::model()->findByPk(10);
$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
$post->delete();

// 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(
‘published’=>array(
‘condition’=>’status=1’,
),
‘recently’=>array(
‘order’=>’create_time DESC’,
‘limit’=>5,
),
);
}

And then use the below statement to query.
$posts=Post::model()->published()->recently()->findAll();

// write in model class to to some ops before saving
public function beforeSave() {
if ($this->isNewRecord)
$this->created = new CDbExpression(‘NOW()’);
else
$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))
->queryRow();
OR
$row = Yii::app()->db->createCommand(array(
‘select’ => array(‘id’, ‘username’),
‘from’ => ‘tbl_user’,
‘where’ => ‘id=:id’,
‘params’ => array(‘:id’=>1),
))->queryRow();

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

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

$users = Yii::app()->db->createCommand()
->select(‘*’)
->from(‘tbl_user’)
->queryAll();

// display SQL statement
$sql = Yii::app()->db->createCommand()
->select(‘*’)
->from(‘tbl_user’)
->text;

// INSERT
// build and execute the following SQL:
// INSERT INTO `tbl_user` (`name`, `email`) VALUES (:name, :email)
$command->insert(‘tbl_user’, array(
‘name’=>’Tester’,
’email’=>’tester@example.com’,
));

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

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

// NEXT
// 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
$post->save();