Page Contents
Overview
In the Ringside Social Application Server, APIs are bundled inside the API container. Through this integration with the API container they are managed and provided a set of services, either by configuration or through programmatic calls.
Default Services
- API Key Authentication
- Call ID checking
- Signature (Secret Key) validation
- Metering/Monitoring support
- REST lifecycle enabling every call to participate in lifecycle
- more to come
Programmatic services (coming in R2)
- Permission checks
- Social Graph validation
- Identity Mapping
- Access to graph data directly
There is a trail that demonstrates how to write a custom API - see Customizing with new APIs
To implement an API you must:
- Pick a domain, package and method name.
- Create a file [domain]/rest/PackageMethod.php
- Create class named PackageMethod and extend the base class Api_DefaultRest
- There are two abstract methods requiring implementation
- validateRequest()
- execute()
- Provide a client for others to use it
Pick a Name. How do APIs get invoked?
The clients that communicate with a Ringside or Facebook server send a remote call with method name equal to '[namespace].[package].[method]'; for example 'facebook.photos.get' or 'ringside.comments.get'. Each of these translate into file and class names as such:
ringside.comments.get = class CommentsGet in file ringside/rest/CommentsGet.php
facebook.photos.get = class PhotosGet in file facebook/rest/PhotosGet.php
When incoming requests are processed, we inspect the method name and determine what the handler name should be, based on the above algorithm. Also, based on the handler name, we provide the default services to ensure the call is authenticated and the appropriate social context is available, including user, network and application information.
These would be packaged into a directory called [domain]/rest/[Package][Method].php in your include_path.
Override Api_DefaultRest
The base class Api_DefaultRest provides some convenience methods, check methods, and abstraction to the social context. Things that are available include:
- Application Id ($this->getAppId())
- Network Id ($this->getNetworkId())
- User Id( $this->getUserId() )
Session is the combination of User+App+Network; persistent information can be pushed into this session:
- setting session value ($this->setSessionValue( key, value ))
- getting session value ($this->getSessionValue( key )
Parameters are also passed through to your API request:
- get all parameters ( $this->getApiParams() )
- get one parameter ( $this->getApiParam( $key ) )
- get a required parameter ( $this->getRequiredParam( $key ) ) which will throw an exception if the parameters has not been set.
- parameters can be checked separately via checkRequiredParam, though getRequiredParam encapsulates this.
Context are the parameters managed by the Ringside instance and are typically required.
- $this->getContext() returns a Api_RequestContext object.
- Api_Request context provides access to specific parameters enabled as part of the request context.
Check methods:
- Is it a default application that is calling? ($this->checkDefaultApp() )
- A default application is a system application allowed to ask deeper questions
- checkRequiredParam()
Database Convenience:
- get database connection for call ($this->getDbConn())
- more to come for database session management...
What to do in the validateRequest()?
The method validateRequest has the following signature:
public function validateRequest()
A typical implementation might be
public function validateRequest( ) {
$this->m_xid = $this->getRequiredApiParam( 'comment_id' );
$this->m_friends = $this->getApiParam( 'friends', 'false' );
}
Things to do within the execute method
The execute method is your opportunity to take the inputs, do some work, and send a response.
Typically in this layer we call the database layer, send messages, or call other APIs. The execute has no parameters as the constructor already digested the social context and parameters.
It is very important to understand the impact of the returned result. This has direct impact on how the response is encoded over the wire back to a remote client. Following the prescribed mechanism ensures client responses are possible with no modification of client code. The next section contains more details.
public function execute() {
$count = RingsideApiDbComments::getCommentCount();
$this->xid, $this->getAppId(), $this->getDbCon() );
$response = array();
$result = $this->getCount();
if ( $result === false ) {
$response['result'] = '0';
} else {
$response['result'] = '' . $result;
}
return $response;
}
Understanding return results
The response from the call be transported over the wire via different formats including JSON encoding, XML response, or serialized php. To support these formats and future formats we require APIs to respond as an associative array (and array of arrays). The best way to understand is to see some examples of returned values and how they get converted into XML.
In all the cases we will make and assumed method ringside.comments.get.
Simple Example
$response = array();
$response['result'] = 0;
would become
<comments_get_response>0</comments_get_response>
Example with list of results
$response = array();
$examples = array();
foreach ( $record as $key=>$row) {
$example = array();
$example ['thing'] = $row[ 'some column' ];
}
$response['comment'] = $example;
return $response;
would become
<comments_get_response list="true">
<comment>
<thing>value of thing</thing>
</comment>
<comment>
<thing>value of thing 2</thing>
</comment>
</comments_get_response>
Writing a Client to connect with API
All the guts of connecting with an API container is already built into the existing clients. We suggest writing a class which uses delegation to offer a remote interface to your APIs. The underlying client will also provide a calling context back to the API container so you don't have to worry about passing around the application id, the user id or the network of the current session.
Example client.
- Your Methods is to get a users comments.
- The remote method name would be ringside.comments.get.
Your client class could be
class CommentsClient {
private $delegate;
public function __construct($delegate) {
$this->delegate = $delegate;
}
public function comments_get( $comment_id )
{
$params = array();
$params['comment_id'] = $comment_id;
$this->delegate->call_method("ringside.comments.get", $params);
}
}
API Example
Here is CommentsCount, located at ringside/rest/CommentsCount.php
class CommentsCount extends Api_DefaultRest{
private $xid;private $aid;
/**
* Validate request.
*/
public function validateRequest( ) {
$this->xid = $this->getRequiredApiParam('xid');$this->aid = $this->getApiParam('aid', $this->getAppId());
}
/**
* Get the count of comments for a given thread.
*
* @return count of comments for a thread
*/
public function execute() {
$this->checkDefaultApp( $this->aid );
$response = array();
$result = $this->getCount();
if ( $result === false ) {
$response['result'] = '0';
} else {
$response['result'] = '' . $result;
}
return $response;
}
/**
* Get the count from DB tier.
*
* @returns true/false
*/
public function getCount( ) {
$count = Api_Dao_Comments::getCommentCount( $this->xid, $this->aid, $this->getDbCon() );
return $count;
}