Saturday, February 2, 2008

Rest in 10 Minutes

Without going into theoretical aspects, I thought it would be helpful for a newcomer to just take a pragmatic approach to get started with REST.

REST stands for REpresentational State Transfer. The key idea behind REST is resources. Everything in the networked world is a resource.
Each resource can be uniquely identified by a URI (E.g: URL's in WWW). WWW is a good example of RESTful design.
These resources can be linked together (E.g: Hyperlinking in WWW).
There's a standardized protocol for client to interact with the resources. (E.g.: Web browsers using HTTP's standard methods such as GET, POST, PUT and DELETE).
It allows you to specify the format in which you want to interact with. (E.g: HTTP Accept headers such text/html, image/jpeg etc.)
It's a stateless protocol. (E.g: HTTP is stateless)

I will now walk you through a simple PHP code snippet to invoke REST services using GET method.

The idea is as follows.
You get the base URL of the resource you want to access. (E.g.: The base URL of Yahoo Traffic REST service is http://local.yahooapis.com/MapsService/V1/trafficData).
You URL encode the parameters expected by the service to indicate your intension. (baseurl?name1=value1&...&namen=valuen)
You get the result back, usually in XML format which you can manipulate easily.

A word about implementations. There are SOAP libraries (e.g.: WSF/PHP) out there which allows you invoke restful services. You can also access such services with those libraries already available. Today, I will take the latter approach and will look into the former approach in a future blog entry.

There are mainly two ways to implement REST clients with built-in PHP libraries.
1. Using cURL
2. Using file_get_contents()

I used the first approach.

Here's how you'd access some the services provided by Yahoo.

Yahoo Locations:

include_once('RESTClient.php');

$base = 'http://local.yahooapis.com/MapsService/V1/geocode';

$params = array( 'appid' => "YahooDemo",
'street' => '271 S River Road',
'city' => 'West Lafayette',
'state' => 'IN',
);

$client = new RESTClient();
$res = $client->request($base, $params);

// Output the XML
echo htmlspecialchars($res, ENT_QUOTES);

$xml = new SimpleXMLElement($res);
echo
"
Latitude : "
.$xml->Result->Latitude."
"
;
echo
"Longitude : ". $xml->Result->Longitude."
"
;
echo
"Address : ". $xml->Result->Address." ".$xml->Result->City." ".$xml->Result->State." ".
$xml->Result->Zip." ".$xml->Result->Country;

?>


Output:
[XML Omitted]
Latitude : 40.419785
Longitude : -86.905912
Address : 271 S River Rd West Lafayette IN 47906-3608 US


Yahoo Traffic:

include_once('RESTClient.php');
$base2 = 'http://local.yahooapis.com/MapsService/V1/trafficData';
$params2 = array( 'appid' => "YahooDemo",
'street' => '701 First Street',
'city' => 'Sunnyvale',
'state' => 'CA',
);

$res2 = $client->request($base2, $params2);

// Output the XML
echo htmlspecialchars($res2, ENT_QUOTES);

?>


Output:
[XML omitted]
Severity[1-5, 5 being the most] : 2
Description : NORTHBOUNDLONGTERM FULL RAMP CLOSURE CONSTRUCTION


Yahoo Maps:

include_once('RESTClient.php');
$base3 = 'http://local.yahooapis.com/MapsService/V1/mapImage';
$params3 = array( 'appid' => "YahooDemo",
'street' => '271 S River Road',
'city' => 'West Lafayette',
'state' => 'IN',
);
$res3 = $client->request($base3, $params3);
$xml3 = new SimpleXMLElement($res3);
echo
".$xml3."'/>
"
;

?>

Output:

As you might have notices I have included 'RESTClient.php' above. Here's the code for the RESTClient class.

//Curl based REST client for GET requests
class RESTClient {
//request takes two parameters
//$baseUrl - base URL of the resource you want to access
//$param - an associative array of parameters you want to pass with the request
public function request($baseUrl, $params) {
$queryString = '';
$responseXml = null;
$response;
$resourceUrl;

foreach (
$params as $key => $value) {
$queryString .= "$key=" . urlencode($value) . "&";
}
$resourceUrl = "$baseUrl?$queryString";



// Initialize the session giving the resource URL
$session = curl_init($resourceUrl);


// Set curl options
curl_setopt($session, CURLOPT_HEADER, true);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);

// Make the request
$response = curl_exec($session);

// Close the curl session
curl_close($session);

// Get HTTP Status code from the response
$statusCode = array();
preg_match('/\d\d\d/', $response, $statusCode);

// Check the HTTP Status code
switch( $statusCode[0] ) {
case
200:
break;
//OK
case 503:
echo(
'Failed: 503 : Service Unavailable.');
break;
case
403:
echo(
'Failed: 403 : Access Forbidden.');
break;
case
400:
echo(
'Failed: 400 : Bad request.');
break;
default:
echo(
'Unhandled Status:' . $statusCode[0]);
}

if (
$statusCode[0] == 200) {
$responseXml = strstr($response, '); //stripping off HTTP headers
}
return
$responseXml;
}
}
?>


No comments: