An Orkut Application via a JSON API

I talked about delegating rendering in Symfony for creating a JSON API. Now here’s a consumer: an Orkut opensocial gadget:

MobshareOrkutAPI = {

	api_url: 'http://api.mobshare/api.php',
	cache_time: 0, //0 to disable

	makeCachedRequest: function(url, callback, params, refreshInterval) {
	  var ts = new Date().getTime();
	  var sep = "?";
	  if (refreshInterval && refreshInterval > 0) {
	    ts = Math.floor(ts / (refreshInterval * 1000));
	  if (url.indexOf("?") > -1) {
	    sep = "&";
	  url = [ url, sep, "nocache=", ts ].join("");, callback, params);

	call: function(module, action, params, callback) {
		var options = {};
		options[] =;
		this.makeCachedRequest(this.api_url + '/' + module + '/' + action + '?' + params, callback, options, this.cache_time);


makeCachedRequest has been plaigarized from the Opensocial documentation and it’s very useful to bust the cache for requests. Also, notice this line for setting the content-type to JSON:

options[] =;

This is how we access that API, a code fragment:

authenticate: function(alias, mobile_no, password) {'user', 'authenticate',
		'alias=' + encodeURIComponent(alias) + '&mobile_no=' + encodeURIComponent(mobile_no) +
			'&password=' + encodeURIComponent(password),
login: function(orkut_response) {
	response =;
	data_success = response['success'];
	data_error = response['error'];

	if(data_success) {
		html = '<h2>Login Successful!</h2>';
		html += '<p>Welcome: ' + + '!</p>';
	} else if(data_error) {
		html = '<h2>Login Unsuccessful!</h2>';
		html += '<p>' + data_error + '!</p>';

	document.getElementById('mobshare_login').innerHTML += html;

Note that is automatically set by Orkut because you passed in the JSON content type; it parses the data received and creates a javascript object. Cool, ain’t it? It’s very easy to create a proper interactive Opensocial app this way.

Delegate Rendering in Symfony

Warning: pretty advanced Symfony ahead: if you’re not familiar with the framework, this wouldn’t make sense.

I recently developed a bare-bones API for Mobshare (it’s not yet live), and to keep everything clean, I abstracted away the rendering bit from the controller to an external class. It ended up being a sweet solution, so here it is!

I wanted this to be a JSONP API (the major use case would be a JS client, and parsing XML etc. via JS is a pain. Besides JSON is much shorter over the wire). I didn’t want to rewrite a lot of code: checking for a callback parameter and wrapping the returned string around the JSON output was just begging to be refactored away. So here it is, a generic Symfony JSON API wrapper class:


class JSONPAPI {

	const CALLBACK_PARAMETER = 'callback';

	var $status;
	var $data;
	var $callback;

	public function __construct($status, $data) {
		$this->status = $status;
		$this->data = $data;

		$callback_parameter_value = $this->getCurrentAction()->getRequestParameter(self::CALLBACK_PARAMETER);
			$this->callback = $callback_parameter_value;

	public function render() {
		$render_text = json_encode(array($this->status => $this->data));

			$render_text = $this->callback . '(' . $render_text . ');';

		return $this->getCurrentAction()->renderText($render_text);

	//hack to get the current action
	private function getCurrentAction() {
		return sfContext::getInstance()->getActionStack()->getLastEntry()->getActionInstance();

	private function setJavascriptHeaders() {
		sfContext::getInstance()->getResponse()->setParameter('Content-Type', 'application/javascript', 'symfony/response/http/headers');

The bits of magic here are the getCurrentAction() function and the render() call. It works on one very simple idea: everything in Symfony can be accessed from the sfContext::getInstance() object, you just need to dig deep enough.

Once you write this boiler-plate code, using it is very elegant. First, subclass it for your API:



class MobshareAPI extends JSONPAPI {


And then, use it like so within your controller:

class userActions extends sfActions

	public function executeAuthenticate() {
		$valid_user = UserPeer::authenticate($this->getRequestParameter('alias'),
			$this->getRequestParameter('mobile_no'), $this->getRequestParameter('password'));
		if($valid_user instanceOf User) {
			$success = new MobshareAPI('success', $valid_user->toArray());
			return $success->render();
		} else {
			$error = new MobshareAPI('error', 'Authentication failed: Alias, mobile number or password invalid.');
			return $error->render();


Note: the rendering has been delegated to the $success and $error MobshareAPI objects. This allows for a really maintainable API. Adding functionality is much simpler since you don’t have to worry about the boilerplate.

You end up calling the API like this:


and you get back data which looks like this:

handler({"success":{"alias":"vish","name":"Vishnu Gopal","photo_mini": ...);

Note that callback handling is done entirely by the API and the controller needn’t worry about this parameter at all!