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

Tips to make your website run faster

  • Minimize HTTP Requests
  • Images : CSS Sprites are the preferred method for reducing the number of image requests. Combine your background images into a single image and use the CSS background-image and background-position properties to display the desired image segment.
  • Use a Content Delivery Network
  • Add an Expires or a Cache-Control Header
  • Gzip Components
  • Put Stylesheets at the Top
  • Put Scripts at the Bottom : The problem caused by scripts is that they block parallel downloads.
  • Make JavaScript and CSS External: Using external files in the real world generally produces faster pages because the JavaScript and CSS files are cached by the browser.
  • Split Components Across Domains : The HTTP/1.1 specification suggests that browsers download no more than two components in parallel per hostname. If you serve your images from multiple hostnames, you can get more than two downloads to occur in parallel.
  • Reduce DNS Lookups : DNS lookups take time. Reducing the number of unique hostnames has the potential to reduce the amount of parallel downloading that takes place in the page. Avoiding DNS lookups cuts response times, but reducing parallel downloads may increase response times.
  • Minify JavaScript and CSS
  • Remove Duplicate Scripts : Due to large number of developers and size of project its possible a script etc may get loaded multiple times.
  • Don’t Scale Images in HTML
  • Avoid Empty Image src
  • Use Profiling tools to identify which parts of your code are consuming more time and more memory
  • Fetch Data in Parallel : (multi curl for PHP, node.js, etc)
  • Use EXPLAIN statement to analyze your SQL queries. Based on that add proper indexes
  • Prepared statements in SQL need to be parsed just once
  • Use Opcode Cache which will save the server from parsing your php again
  • Use Memcache DB for storing frequent calls to the database
  • Use MySQL Master Slave for faster read access
  • See if schema needs to be split vertically or horizontally for faster access

Salted Password Hashing – Doing it Right

Salting inherently makes your user’s passwords better automatically by prepending or appending a random string. So lookup tables become useless.
But if the password hash and salt table is compromised then salt will not help (as in LinkedIn case). LinkedIn should have been using bcrypt, which is an adaptive hash that would have slowed the brute force time down to the order of 10s of hashes per second.

Cookie vs Sessions

Both cookies and sessions are available to you as a PHP developer, and both accomplish much the same task of storing data across pages on your site. However, there are differences between the two that will make each favourable in their own circumstance.

Cookies can be set to a long lifespan, which means that data stored in a cookie can be stored for months if not years. Cookies, having their data stored on the client, work smoothly when you have a cluster of web servers, whereas sessions are stored on the server, meaning in one of your web servers handles the first request, the other web servers in your cluster will not have the stored information.

Sessions are stored on the server, which means clients do not have access to the information you store about them – this is particularly important if you store shopping baskets or other information you do not want you visitors to be able to edit by hand by hacking their cookies. Session data, being stored on your server, does not need to be transmitted with each page; clients just need to send an ID and the data is loaded from the local file. Finally, sessions can be any size you want because they are held on your server, whereas many web browsers have a limit on how big cookies can be to stop rogue web sites chewing up gigabytes of data with meaningless cookie information.

So, as you can see, each have their own advantages, but at the end of the day it usually comes down one choice: do you want your data to work when you visitor comes back the next day? If so, then your only choice is cookies – if you have any particularly sensitive information, your best bet is to store it in a database, then use the cookie to store an ID number to reference the data. If you do not need semi-permanent data, then sessions are generally preferred, as they are a little easier to use, do not require their data to be sent in entirety with each page, and are also cleaned up as soon as your visitor closes their web browser.

MyISAM vs InnoDB

MyISAM was the default storage engine chosen by MySQL database, when creating a new table. But since 5.5 version, InnoDB is the default storage engine.

The major differences between these two storage engines are :

  • InnoDB supports transactions which is not supported by tables which use MyISAM storage engine. InnoDB table supports foreign keys, commit, rollback, roll-and forward operations
  • InnoDB has row-level locking, relational integrity i.e. supports foreign keys, which is not possible in MyISAM.
  • InnoDB ‘s performance for high volume data cannot be beaten by any other storage engines available.
  • The size of MyISAM table can be up to 256TB, which is huge. InnoDB tables can be upto 64 TB
  • In addition, MyISAM tables can be compressed into read-only tables to save space.

Tables created in MyISAM are known to have higher speed compared to tables in InnoDB. But since InnoDB supports volume, transactions, integrity it’s always a better option which you are dealing with a larger database. It is worth mentioning that a single database can have tables of different storage engines.

MyISAM is good for read-heavy applications, but it doesn’t scale very well when there are a lot of writes. Even if you are updating one field of one row, the whole table gets locked, and no other process can even read from it until that query is finished. MyISAM is very fast at calculating SELECT COUNT(*) types of queries.

InnoDB tends to be a more complicated storage engine and can be slower than MyISAM for most small applications. But it supports row-based locking, which scales better. It also supports some more advanced features such as transactions.

Advantages and Disadvantages of AJAX


  • Your page will be more pleasant to use, when you can update parts of it without a refresh, which causes the browser to flicker and the statusbar to run.
  • Because you only load the data you need to update the page, instead of refreshing the entire page, you save bandwidth.


  • Because the updates are done by JavaScript on the client, the state will not register in the browsers history, making it impossible to use the Back and Forward buttons to navigate between various states of the page.
  • For the same reason, a specific state can’t be bookmarked by the user.
  • Data loaded through AJAX won’t be indexed by any of the major search engines.
  • People using browsers without JavaScript support, or with JavaScript disabled, will not be able to use the functionality that you provide through AJAX.