December 7, 2009

Building a REST (or REST-like) LAMP Web Service - Part 1

Last week a colleague asked me about web services. Specifically, he wanted to know what a web service was, and why one would deploy a web service. I answered his questions to the best of my abilities; I told him that a web service is an API that allows two applications to share data in an agreed upon format, such as XML or JSON. As for the why part, I told him that web services are deployed in situations where two or more decoupled applications want (or need) to share information.

Since he'd taken such a keen interest in web services, and since I know he's familiar with web services, I figured I'd post a brief tutorial on how to create and deploy a REST (or REST-like) web service on a LAMP platform. For the purpose of this tutorial, the P in LAMP will be PHP. I will assume that you have a strong working knowledge of XML and PHP.

Before we get started, it's worth mentioning that there is no single way to set up and run a REST web service on the LAMP platform, so in reality the method I'm going to show you today is just one way of doing it. There are plenty of other equally valid ways of setting up and running web services on the LAMP platform.

We will need at least 3 files to get started:
  • .htaccess - This file will redirect URIs to our web service endpoint.
  • index.php - This file will be our web service endpoint. It will parse URIs and pass requests to an instance of our web service.
  • webservice.php - This class will be the workhorse of our application - it will handle data retrieval, formatting, etc.

Designing the Web Service

I'm not going to get too deep into REST theory and practice here. If you want a more in-depth (but accessible) treatment of REST principles, I recommend checking out Ryan Tomayko's excellent article, "How I Explained REST to My Wife." The basic gist of RESTful web services is that they use a combination of URIs and request methods (GET, POST, PUT, DELETE) to execute a function and return a response. For this tutorial, we're going to create a web service that stores and retrieves information about a set of books.

When designing a RESTful web service one needs to consider both the URI scheme that will be used, as well as the data scheme that will be used. Let's start by figuring out our data schemes. For simplicity's sake, let's say that our web service will provide information about books and their authors.

For books, we want to store and retrieve the following information:
  • Book ID
  • Title
  • Author's Name (in Last, First format)
For authors, we want to store and retrieve the following information:
  • Author ID
  • Last Name
  • First Name
Obviously we could have a lot more information on both books and authors, but for this example what we have now will suffice. So, now, let's take a look at what we want our XML entities for both book and author to look like:

<book>
  <id>12345</id>
  <bookTitle>Learning XML, Second Edition</bookTitle>
  <author>Ray, Erik</author>
</book>


<author>
  <id>321</id>
  <lastName>Ray</lastName>
  <firstName>Erik</firstName>
</author>



If we have multiple books or authors, we'll just wrap them in plural tags, like this:

<books>
  <book>...</book>
  <book>...</book>
</books>


<authors>
  <author>...</author>
  <author>...</author>
</authors>


Now that we've figured out our data structures, we need to think about our URI schemes. Remember that we need to consider both the URI and the request method...


URI
Method
Description
/books/
GET
Gets a list of all books
/book/{id}/
GET
Gets the book specified by {id}
/book/new/
POST
Creates a new book
/authors/
GET
Gets a list of all authors
/author/{id}/
GET
Gets the author referenced by {id}
/author/new/
POST
Creates a new author.

We have both our data structures and our URIs defined; now it's time to take a look at our web service implementation.

Implementing the Service: .htaccess and index.php

We'll start the web service implementation process by setting up our .htaccess and index.php files. We'll cover the web service class implementation in Part 2 of the article.

.htaccess is a file that is used by the Apache HTTP server to determine how files on your server are accessed on a per-directory basis. I won't explain it fully here, but if you want to know more about .htaccess and how you can use it, feel free to check out Apache's .htaccess file tutorial.

For our purposes, we're going to take advantage of Apache's URI rewriting engine to redirect requests to specific URIs to our index.php file. Open up a plain text editor, such as notepad, and let's begin:

The first two lines in our .htaccess file are the following:
RewriteEngine on
RewriteBase /

The first line is fairly self explanatory. The second line simply tells the web server that the base virtual path to our web service is "/" (for more information on how RewriteBase works, read this Apache doc).

The next line in our .htaccess file is this:
RewriteCond %{REQUEST_FILENAME} !-s 

It may look crazy, but the line above is simply telling the server that it should only re-direct requests to our index.php file if the requested file does not already exist in this directory. This is useful in the case that we want to store other resources in this directory, such as documentation files.

Finally, the last line in our .htaccess file handles the redirection to index.php:
RewriteRule ^(.*)$ /index.php/$1 [L]

Once again, it looks like we have a lot of stuff here, and in truth we do. In practice, here's what the .htaccess file does:

In your browser, you type the following: http://www.some-domain.com/authors/

The .htaccess file at http://www.some-domain.com/ intercepts your request and checks the directory to see if a resource named /authors/ actually exists. If it does not exist, your request is rewritten as http://www.some-domain.com/index.php/authors/

This redirection happens on the server, however, not in your browser. So, the URI that you see in your browser is still http://www.some-domain.com/authors/

Let's move on and implement index.php. We'll start by getting the request method and path information.

$method = $_SERVER['REQUEST_METHOD']; //e.g. GET, POST
$path_info = $_SERVER['ORIG_PATH_INFO']; //e.g. index.php/authors/
$uri_parts = parse_uri($path_info);
$resource_type = $uri_parts['resource_type']; //e.g. "authors"
$request = $uri_parts['request']; //anything after the resource type

$service = new BookService($method,$resource_type,$request);
$service.execute();

function parse_uri($path_string)
{
  // $path_string is something like
  // 'index.php/authors/'
  $path_parts = explode("/",$path_string);
  $restype = $path_parts[1];
  $req = $path_parts[2];

  $ret_array = array();
  $ret_array['resource_type'] = $restype;
  $ret_array['request'] = $req;

  return $ret_array;
}

That's all you need for your index.php file. In the next installment we'll define the BookService class and provide the functionality needed to get the service up and running. In the meantime, if you have questions or comments feel free to post them here or email brian (at) brian-driscoll (dot) com.
Post a Comment