Dashboard > ringside > ... > Getting Started Trail Map > Customizing with new APIs
Customizing with new APIs Log In | Sign Up   View a printable version of the current page.

The documentation below is for a trail for the Continuous build, if you are looking for the trail for the STABLE build.
http://wiki.ringsidenetworks.org/pages/viewpage.action?pageId=1312091

Theme of this Trail
In this trail, you will learn how you can customize a Ringside Social Application Server with your own API extensions. This allows you to add additional REST functions directly to the Ringside server which can then be shared across all applications that are deployed in your Ringside environment.

Setup

All source code for this trail can be found in one of three places:

  1. [installation_dir]/apps/ringside/htdocs/trail_map_5 (if you used the Ringside installer)
  2. Download it here as either a tarball (for Linux/Mac) or a zip file (for Windows)
  3. Build it yourself. This assumes you have the Ringside source checked out from SVN. Go to your working copy's /demo-apps directory and run the build by executing phing. The source for this trail will then be located here (relative to your SVN working copy): dist\demo-apps\stack\apps\ringside\htdocs\api\trail_map_5
In order for this demo to work, you must have at least one friend. If you created a new user and have not added any friends, you must add at least one friend before trying the demo.

Implementing a Suggestion API

For a good introduction on writing API implementations, see Getting Started Writing APIs.

In Trail 4 we had a class called SuggestionUtils which directly called the database to create/get topics and suggestions. As an application developer, you might want to expose these services via a REST-based API, so that other application developers can utilize your suggestions application functionality. This trail will go over how to implement these API calls within the Ringside REST server, as well as how to create a client to provide a convenient interface for calling these methods.

Step 1: Create the API Implementations

First we'll create a REST call for adding a suggestion to the database. As mentioned in Getting Started Writing APIs, our API class should extend Api_DefaultRest and implement the \validateRequest() and execute() methods. The method name of our REST call will be 'ringside.suggestion.add', which implies a class name of SuggestionAdd. The Ringside REST server will try and include the file 'ringside/rest/SuggestionAdd.php', so make sure the file is stored in the proper sub-directories under a directory in your PHP include_path.

ringside/rest/SuggestionAdd.php

<?php
require_once( "ringside/api/DefaultRest.php" );

class SuggestionAdd extends Api_DefaultRest
{

	/**
	 * String representing the topic of discussion.
	 */
	protected $m_topic;
	
	/**
	 * The UID of the user who created the topic.
	 */
	protected $m_owner;
	
	/**
	 * The actual suggestion. 
	 */
	protected $m_suggestion;
	
	/**
         * The API key of the application containing the topic.
         */
	protected $m_appApiKey;
	

	public function validateRequest( )
	{
		
		$this->m_topic = $this->getRequiredApiParam( 'topic' );
		$this->m_owner = $this->getRequiredApiParam( 'owner' );
		$this->m_suggestion = $this->getRequiredApiParam( 'suggestion' );
		$this->m_appApiKey = $this->getRequiredApiParam( 'app_api_key' );
	}
	
	public function execute()
	{
		//construct insertion SQL
		$sql = 'INSERT INTO suggestions SET ' .
    				 "topic='{$this->m_topic}'," .
    				 'uid=' . $this->getUserId() .
    				 ", suggestion='{$this->m_suggestion}', " .
    				 "api_key='{$this->m_appApiKey}', " .
    				 "owneruid={$this->m_owner}";
		
		//get DB connection
		if (!($db = $this->getDbCon())) {
			throw new Exception('Could not connect to DB: ' . mysql_error());
		}
		//execute query
		if (!mysql_query($sql, $db)) {
			throw new Exception('Error inserting into DB: ' . mysql_error() . "\nSQL='$sql'");
		} 
		
		//if made it this far, then return successfully
		return true;	
	}
}
?>

Now we'll create a REST call for getting a list of topics, under the method name 'ringside.suggestion.getTopics'.

ringside/rest/SuggestionGetTopics.php

<?php
require_once( "ringside/api/DefaultRest.php" );

class SuggestionGetTopics extends Api_DefaultRest
{
	/**
	 * Array of friend IDs to query topics from.
	 */
	protected $m_friends;
	

	public function validateRequest()
	{
				
		$this->m_friends = explode(',', $this->getRequiredApiParam( 'friends' ) );		
	}
	
	public function execute()
	{
		//get DB connection
		if (!($db = $this->getDbCon())) {
			throw new Exception('Could not connect to DB: ' . mysql_error());
		}
		
		//construct query
		$sql = "SELECT DISTINCT topic, owneruid FROM suggestions WHERE " .
				 "owneruid IN ({$this->getUserId()}";
		if (count($this->m_friends) > 0) {
			$sql .= ',' . implode(',', $this->m_friends);
		}
		$sql .= ') ORDER BY topic';
		
		//execute query
		$results = mysql_query($sql, $db);
		if (!$results) {
			throw new Exception('Could not execute query: ' . mysql_error() . "\nSQL='$sql'");
		}
		$response = array();
		$response['topic'] = array();
		
		//create response
		while($row = mysql_fetch_assoc($results)) {
			$response['topic'][] = $row;
		}
		return $response;
	}
}
?>

And last, we'll create a REST call for getting all suggestions for a user and optionally that user's friends, under the method name 'ringside.suggestion.get'.

ringside/rest/SuggestionGet.php

<?php
require_once( "ringside/api/DefaultRest.php" );

class SuggestionGet extends Api_DefaultRest
{
	/**
    * The API key of the application containing the topic.
    */
	protected $m_appApiKey;
	
	/**
	 * Array of friend IDs to query topics from.
	 */
	protected $m_friends;
	
	function beginsWith( $str, $sub ) {
		return ( substr( $str, 0, strlen( $sub ) ) === $sub );
	}
	function endsWith( $str, $sub ) {
	   return ( substr( $str, strlen( $str ) - strlen( $sub ) ) === $sub );
	}


	public function validateRequest( )
	{

		$this->m_friends = $this->getRequiredApiParam( 'friends' );
		$this->m_appApiKey = $this->getRequiredApiParam( 'app_api_key' );
		
		if($this->endsWith($this->m_friends, ','))
		{
			$this->m_friends = substr($this->m_friends, 0, strlen($this->m_friends) - 1);
		}
	}
	
	public function execute()
	{
		//get DB connection
		if (!($db = $this->getDbCon())) {
			throw new Exception('Could not connect to DB: ' . mysql_error());
		}
		
		//construct query
		$sql = "SELECT * FROM suggestions WHERE api_key='{$this->m_appApiKey}' " .
				 " AND owneruid IN ({$this->getUserId()}";
		if (strlen($this->m_friends) > 0) {
			$sql .= ",$this->m_friends";
		}
		$sql .= ') ORDER BY topic, sid';

		//execute query
		$results = mysql_query( $sql, $db);
		if ( mysql_errno($db) > 0  && !$results) {
			throw new Exception('Could not execute query: ' . mysql_error() . "\nSQL='$sql'");
		}

		$suggestions = array();
  		//create response
  		while($row = mysql_fetch_assoc($results)) {
   			$suggestions[] = $row;
  		}
  		
  		$response = array();
  		if (!empty( $suggestions ) ) { 
     		$response['suggestions'] = $suggestions;
  		} 
  		else {
     		$response['result'] = '';
 		}
 		return $response;
	}
}
?>

Step 2: Create the Client Interface

The REST calls are to be put in the include_path of your Ringside server (Note: the installer will do this automatically for you). Now we will create a client class that can be used by other applications (or your own) to call the suggestion API. This client class typically will not exist on the same server as the REST call implementations, although for the purposes of this trail it does.

Our SuggestionClient will delegate API calls to an instance of RingsideApiClientsRest. Our methods will construct arrays of parameters and pass them to the delegate instance, which then sends a request to the REST server endpoint, restserver.php. In contrast to the suggestion API implementations, the client will sit along side of your application code.

ringside/api/clients/SuggestionClient.php

<?php
require_once('ringside/api/clients/RingsideRestClient.php');

class SuggestionClient
{
   public $delegate;
    
   /**
    * Constructs a Ringside-specific REST client.
    */
   public function __construct($delegate) {
      $this->delegate = $delegate;
   }

   /**
    * Add a suggestion to a given topic.
    * @param $topic String name of the topic.
    * @param $owner Integer uid of topic owner.
    * @param $apiKey API key of app that owns topic.
    * @param $suggestion String representing suggestion to topic.
    */
   public function suggestion_add($topic, $owner, $apiKey, $suggestion)
   {
      //construct the parameters
      $params = array();
      $params['topic'] = $topic;
      $params['owner'] = $owner;
      $params['app_api_key'] = $apiKey;
      $params['suggestion'] = $suggestion;

      //make a call to the underlying REST client to add a suggestion
      return $this->delegate->call_method("ringside.suggestion.add", $params);
   }

   /**
    * Get all suggestions for a given API key and user.
    * @param $apiKey API key of app that owns topic.
    * @param $friends Array of friend UIDs (optional)
    */
   public function suggestion_get($apiKey, $friends = array())
   {
      //construct the parameters
      $params = array();
      $params['app_api_key'] = $apiKey;
      $params['friends'] = $friends;

      //make a call to the underlying REST client to add a suggestion
      $response =  $this->delegate->call_method("ringside.suggestion.get", $params);
      if ( empty ($response) ) { 
         $response = array();
      }
      return $response;
   }

   /**
    * Get all suggestions for a given API key and user.
    * @param $friends Array of friend UIDs (optional)
    */
   public function suggestion_getTopics($friends = array())
   {
      //construct the parameters
      $params = array();
      $params['friends'] = $friends;

      //make a call to the underlying REST client to add a suggestion
      $response = $this->delegate->call_method("ringside.suggestion.getTopics", $params);
      if ( empty ($response) ) { 
         $response = array();
      }
      return $response;
   }
}

?>

Step 3: Putting it all Together

Now that we have a client class which provides a convenient interface to our suggestion API, we'll modify SuggestionUtils.php from Trail 4 to use this client instead of making DB calls directly.

SuggestionUtils.php

<?php
require_once('config.php');
require_once('ringside/api/clients/RingsideApiClients.php');
require_once('ringside/api/clients/SuggestionClient.php');

class SuggestionUtils
{
	static private function getSuggestionClient()
	{
	   	$client = new RingsideApiClients( Config::$api_key, Config::$secret );
	   	$uid = $client->require_login();
	   	
	   	$delegate = $client->api_client; 
		$obj = new ReflectionObject( $delegate );
	   	$suggestionClient = new SuggestionClient( $delegate );
	   	
	   	return $suggestionClient;
	}

	/**
	 * Saves a suggestion
	 */
	static public function createSuggestion($topic, $suggestion, $owner)
	{
		$client = self::getSuggestionClient();
		$client->suggestion_add($topic, $owner, Config::$api_key, $suggestion);
	}

	/**
	 * Returns suggestions for topics from this user or their friends
	 */
	static public function getSuggestions() 
	{
		$client = self::getSuggestionClient();
		$friends = $client->delegate->friends_get();
		
		$resp = $client->suggestion_get(Config::$api_key, $friends);
		
		if (!$resp)  return array();
		return $resp;
	}

	/**
	 * Returns all the topics for this user
	 */
	static public function getTopics()
	{
		$client = self::getSuggestionClient();		
		$friends = $client->delegate->friends_get();
		$resp = $client->suggestion_getTopics($friends);
		if (!$resp) return array(); 
		return $resp;
	}
}
?>

Trail 5 Directory Structure

  • trail_map_5/
    • add.php: interface for adding a suggestion
    • config.php: configuration for suggestion app
    • index.php: controller class for suggestion app
    • list.php: interface for listing suggestions
    • SuggestionUtils.php: suggestion utility class
    • ringside
      • api
        • clients
          • facebook*.php: facebook PHP client classes
          • RingsideApiClients*.php: Ringside PHP client classes
          • RingsideRestClient.php: Ringside delegating client class
          • SuggestionClient.php: suggestion client

Next Trail

Go to the next trail to learn how to create your own custom XML tags for use by applications.

Added by Richard Friedman , last edited by John Mazzitelli on May 27, 2008  (view change)
Labels: 
(None)