Anash's Knowledge Base

Navigation

REST implementation in Shindig PHP version

Author: Anash P. Oommen



Overview

REST based services are a new addition to OpenSocial 0.8 standard. The REST services provide a mechanism for 3rd party servers to integrate with OpenSocial containers. In this article, we examine the REST implementation in the PHP version of Shindig, a reference implementation of Shindig. Since the REST Implementation in PHP version of Shindig closely follows its Java counterpart, we will keep this discussion to minimal details. We will examine how PeopleService handles a simple request. Note that the other services have similar flow of logic, and hence it should be easy to understand these services as well.

About REST services

Refer to Rajdeep’s article.

Details

All the REST service requests are handled by the RestServlet class, located in php\src\social-api\http\RestServlet.php. Shindig PHP version uses mod_rewrite and .htaccess configuration to ensure that all requests are routed to index.php. index.php examines the request url, and route all urls beginning with /social/rest to RestServlet.php.

To aid our futher discussion, let us consider a simple REST service request to PeopleService:

http://localhost:8000/shindig/php/social/rest/people/john.doe/@friends?st=a:a:a:a:a:a

This REST request returns all the friends of the user with id=john.doe. Let us examine how this request is handled by Shindig PHP.

Step 1: index.php

Shindig PHP uses mod_rewrite and .htaccess configurations to make sure that all the requests are redirected to index.php. index.php removes the web_prefix (defined in config/container.php) from the url. It then examines the url prefix to decide which class should handle an incoming request. Since our request starts with /social/rest, this request is redirected to RestServlet class. Since the HTTP method is GET, RestServlet::doGet() will handle this request.

Step 2: RestServlet::doGet()

RestServlet begins by extracting the security token parameter from the URL and creating a security token object out of it. This security token will later determine if the request is to be serviced or not. RestServlet will then determine the output format requested by the caller. RestServlet will then call the handleRequest() method to handle the request, and then outputResponse() to create the HTTP response.

Understanding the security token

RestServlet uses a security token to determine if the incoming REST request should be serviced or not. The service token is often provided by the caller as part of the Request URL. RestServlet uses an internal method named getSecurityToken() to create a security token.

getSecurityToken() begins by extracting $_GET[‘st’] from the request. This parameter should be of the form OWNER_KEY: VIEWER_KEY: $APP_KEY: DOMAIN_KEY: APPURL_KEY: MODULE_KEY. getSecurityToken() parses and splits the tokens, and constructs a SecurityTokenDecoder object. It then decodes the string token into a SecurityToken object, by invoking the createToken() method. SecurityToken internally uses a BlobCrypter to sign the Security Token. The default implementation uses 3 classes – BasicSecurityTokenDecoder, BasicSecurityToken and BasicBlobCrypter. BasicSecurityToken uses BasicBlobCrypter to encrypt its token in AES 128 bit format in CBC mode, and then use SHA1 algorithm to sign the encrypted token. It is then stored internally in base64 encoded format.

Shindig PHP provides a pluggable SecurityToken mechanism. One can decide to write his own version of SecurityTokenDecoder, SecurityToken and BlobCrypter objects. To substitute one’s own classes for the basic classes provided by the framework, provide your classname against ‘security_token_signer’ key in the config/container.php file. Also, in case you decide to keep the Basic classes itself, then you can change the encryption key for AES and signing key for SHA1 by changing the 'token_cipher_key' and 'token_hmac_key' settings respectively.

Understanding the output formats

Shindig PHP uses $_GET[‘format’] or $_POST[‘format’] to decide the response format. The supported values and their corresponding encodings are:

'json' : 'application/json'
'atom' : 'application/atom+xml'
'xml'  : 'application/xml'

Step 3: RestServlet::handleRequest()

As the name suggests, handleRequest() method contains the whole logic for handling the REST Request. handleRequest() begins by creating a RestRequest object. The RestRequest object requires several inputs, like REST Params, Request Params and Request Route. handleRequest() invokes several internal methods to extract these parameters from the HTTP request. The significant ones are listed below:

  • getListParams(): breaks the REST url into its components. (e.g. /people/john.doe/@friends is split into ['people', 'john.doe',  '@friends].
  • getRouteFromParameter(): decides the route of the request traversal from the URL. (e.g. people, person, activities, etc.)
  • getRequestParams(): decodes and extracts the additional normal HTTP params ($_POST, $_GET etc.). These data are typically consumed by the individual service providers like PeopleService.

Once the RestRequest object is constructed, handleRequest() constructs an appropriate DataRequestHandler object, based on the request route. It then calls handleMethod() of the newly constructed DataRequestHandler object. Shindig PHP currently supports the following DataRequestHandler objects:

'people': 'PeopleHandler'
'activities': 'ActivitiesHandler'
'appdata': 'AppDataHandler'
'messages': 'MessagesHandler'

Since our request aims at retrieving the list of friends, the DataRequestHandler is a PeopleHandler object.

Step 3.1: DataRequestHandler::handleMethod()

Each DataRequestHandler has methods of the form handleXXX (e.g. handleGet(), handlePost() etc.) to handle the corresponding type of HTTP request. Each DataRequestHandler in turn uses an appropriate Service object to handle the request. The four services defined so far are ActivitiesService, PeopleService, AppDataService and MessagesService. The DataRequestHandler forwards the request to an appropriate Service object to get the data. For example, in our request, PeopleHandler will forward the HTTP request to PeopleService.

Shindig PHP provides a default Service class called JsonDbOpensocialService. This class implements ActivitiesService, PeopleService, AppDataService and MessagesService. This class provides a file-based JSON database. This class reads from a file named canonicaldb.json, handles the data requests, and writes the (updated) JSON object back onto the disk. While this simplistic implementation is useful for testing Shindig, a more serious production-based implementation should replace JsonDbOpensocialService with its own DataProvider. (say, MySqlDbOpenSocialService).

The service classes provided by Shindig PHP are again pluggable; to configure your own classes instead of JsonDbOpenSocialService, you have to modify the following keys in your config/container.php

'people_service' => 'JsonDbOpensocialService',
'activity_service' => 'JsonDbOpensocialService',
'app_data_service' => 'JsonDbOpensocialService',
'messages_service' => 'JsonDbOpensocialService',

Each Service object has a corresponding get() method, which will fetch the requested Data. For example, PeopleService has a getPeople() method, which will retrieve the list of requested people.

Step 3.2: PeopleService::getPeople()

This function does all the data processing (finally…). This function takes several parameters to customize the data requests. The supported params are:

$userId: The user id, as mentioned in the REST url. e,g. john.doe
$groupId : The group id, as mentioned in the REST url: e.g. @friends.
$sortOrder: Sort order for records - name, topfriends etc.
$filter: filtering conditions for records. E.g. all, hasApp, topFriends etc.
$first : Start index for returned list - zero based
$max: Max values to return, default 20
$profileDetails: Fields to return - default are name, id, thumbIcon
$networkDistance: network distance to be used while searching the social graph: default is zero
$token: SecurityToken, as constructed by RestServlet::doGet(). This token determines if the request can actually be handled or not.

The PeopleService will use the above parameters to search, the database (in our case, canonicaldb.json) to fetch and return the relevant records. The actual implementation here will depend on the data store mechanism used by that implementation. A database based system might run a query, a file based system (like JsonDbOpensocialService) might parse the file and then return the relevant objects.

The getPeople() method returns a collection of Person objects, which is returned to RestServlet::doGet()

Step 4: Generating the Output content

Based on the output format requested by the caller, RestServlet will construct an appropriate OutputConverter object. Since we haven’t mentioned a specific format as part of our request, JSON format will be assumed by the server. So, the RestServlet will use an instance of OutputJsonConverter. The outputResponse() method of this class converts the RestResponse into a JSON string. This string is then returned as HTTP response.