Today we will discuss a REST API. We’ll briefly go over what it is and then we’ll implement one from both the server and client perspective.
What is a REST API
A lot of public APIs are REST APIs and knowing how to use them, interact with them and understanding what goes on in the backend can help you leverage a lot of services available. REST stands for “Representational State Transfer” which is a fancy way of saying when you contact the server, you can expect a response. REST APIs are used everywhere, from Google, to Twitter, from Facebook to Amazon. In fact, Amazon’s REST API is used in the saAlbumCoverArt download which downloads music album cover images.
Providing a REST API to your application allows other programmers or developers to hook into your web site. For Twitter, you contact the REST API to get anything from a follow list to recent messages (direct and public). It sounds really cool, ‘REST API’, really programmy, but it really is nothing special. We’ll go through a full example of a REST api from the client request to the server outputting the response.
An Example of a REST API request
We’ll pretend that Simply Amused provided an API allowing you to delete users. For now we’ll ignore the fact that this is completely insecure and dangerous. A REST API has a number of steps involved and has some specific requirements and assumptions.
- The client – our fictional program that will contact the server
- The server – in this case, it’s simplyamused.com
- Assumption: The API will return it’s result in XML.
The structure will look like this:<result> <code>1 | 0</code> <message>Message</message> </result>
Let’s take a look at a full example, complete with controllers, models, exceptions and object orientation. We will use Perl on the client script, and PHP for the backend.
1. The Client – Make the request
The client script will make a HTTP request of the server.
http://simplyamused.com/api.php?action=deleteUser&userId=2
The request looks like any other URL that you would see on the Internet. Looking at the GET variables, it’s a rather simple API to use. While our example URL is simple, in practice, you will find the URLs will look quite long as there is usually a token or hash to authenticate the request. For our example though, we will simply the API.
The client script that utilizes the API is written in Perl. The reason it is in Perl is to show you that the REST API allows two different environments, languages or servers to talk to each other in a pre-defined way. This is the true power of a REST API. The client script doesn’t care that the server used PHP and that it uses Perl.
#!/usr/bin/perl
use strict;
use XML::Simple;
use LWP::Simple;
use Data::Dumper;
my $result = get('http://simplyamused.com/api.php?action=deleteUser&userId=2');
my $xmlResult = XMLin($result);
if ($xmlResult->{'result'}->{'code'} == 1)
{
print $xmlResult->{'result'}->{'message'} . "\n";
}
print Dumper($xmlResult);
1;
The client script makes the request using Perl’s LWP module and then parses the XML for parsing to the XML::Simple module. The client script could be part of an automated provision/de-provision system, or it could simply be a handy script used to delete people.
2. The Server – Delegate the request
In our example above, the server used a file named api.php to handle the request, and had a required argument passed to it; action = deleteUser. The action variable determines what class api.php will call. The file api.php will delegate the actual work of deleting a user to the appropriate class based on the action variable. Consider this code:
' . "\n
%d\n
%s \n
";
try {
// remove any unexpected characters from the action variable
$action = preg_replace('/[^a-z0-9_]+/i', '', $_GET['action']);
if (!isset($action) || empty($action))
{
throw Exception('Invalid API request');
}
$className = $action . 'API';
if (class_exists($className)
{
$ApiCall = new $className();
$ApiCall->run();
printf($xmlFormat, 1, $ApiCall->getSuccessMsg());
}
else
{
throw new Exception('Invalid API request');
}
}
catch (Exception $e)
{
printf($xmlFormat, 0, $e->getMessage());
// output an XML response
}
Our file api.php has delegated the request to the appropriate class.
Every [action]Api class will implement a run() method and that method will attempt to complete the request. If at any time, an exception is thrown, as a way to kill the script due to an error in input or processing, we can output our error XML response. Just like the run() method, every [action]Api class will implement a getSuccessMsg() method which returns a string used for the success message.
While I have chosen not to show it, all [action]Api classes should either implement an API Interface or extend an abstract API class. This will help define and ensure all API classes implement our two methods.
The use of exceptions allows our API to return a result even if something failed or has gone horribly wrong on the backend. Using exceptions in this method allows us to still output the expected API response so that client scripts or applications do not hang if an invalid response is sent. This is very important when building an API.
The output structure is defined in the $xmlFormat declaration at the top of api.php. Since our API is simple, and for brevity, I have chosen this method to output XML. It’s a quick hack to show how it works, not necessarily to be used as-is.
3. The Server – Handle the request
Since api.php has instantiated the deleteUserApi, let’s take a look at this object.
// Class deleteUserAPI.class.php
class deleteUserApi extends AbstractAPI
{
protected $this->userId;
public function __construct()
{
$this->userId = intval($_GET['userId']);
}
public function getSuccessMsg()
{
return 'Successfully deleted the user ' . $this->userId;
}
public function run()
{
// UserModel::deleteUser executes the following SQL and returns bool:
// 'DELETE FROM users where userId= ' . $this->getOption('userId');
if (!UserModel::deleteUser($this->userId))
{
throw new Exception('Could not delete the user $this->userId);
}
return true;
}
}
It’s a simple class, where the run() method calls the model and deletes a user. If it fails, for whatever reason, it will throw an Exception which will be caught in api.php. If we wanted to add a new API command we would just add another class ensuring we implement the methods run() and getSuccessMsg() while ensuring all errors checking we do throws an Exception.
In Conclusion…
Rest APIs are very powerful. They allow different environments to communicate with each other and interact with one another. In today’s “connected world” Rest APIs are becoming ever more popular and knowing how to interact with and create them will be a benefit.
While the code I presented above is not robust, it does show what it takes to get an API running from both ends. The concepts are simple once broken down, and using objects to handle responses means your api.php file can be very generic by exploiting the fact that classes can have the same method in each