PHP Rest Server (part 1 of 3)
Monday, September 1. 2008
I recently had reason to write a REST server in PHP, which was very interesting. There aren't a whole lot of resources on this topic around so I thought I'd write an outline of what I did. There is quite a lot to it so I'm publishing in multiple sections - this is part 1, which covers the central functionality and handling the incoming request.
The main functionality of the service was written in a class that had no awareness that it was a service - this is a similar approach to the one I described when I wrote about the PHP Soap Server - start with a normal functioning class and write some unit tests for it. The example I'm using today looks like this (my real version actually connects to the database and stuff but this is a nice mock of passing in a number and getting back an array):
class Library {
public function getUserDetails($user_id) {
$details = array(
"user_id" => $user_id,
"name" => 'Joe Bloggs',
"email" => 'joe@example.com');
return $details;
}
}
In the soap article, you can see that wrapping a class takes just a few lines - for REST more code is required, but the idea is completely the same. In actual fact we started out with this as a soap service but then it was switched to rest - I only had to re-write the wrapper stuff and not any of the core functionality. Using the wrapper approach would also allow services to be published in multiple ways with the same underlying codebase.
First of all I wrote a .htaccess file to direct all requests to the one controller file - so that all the different URLs would be handled in the same way.
As the requests came into here, I grabbed the data I needed and initialised the service class, something like this:
$service = new Rest_Service();
// instantiate the main functional class and pass to service
$library = new Library();
$service->setLibrary($library);
// create a response object and pass to service
$response = new Response();
$service->setResponse($response);
// set up some useful variables
$service->url = $_SERVER['REQUEST_URI'];
$service->method = $_SERVER['REQUEST_METHOD'];
$service->getArgs = $_GET;
$service->postArgs = $_POST;
parse_str(file_get_contents('php://input'), $service->putArgs);
parse_str(file_get_contents('php://input'), $service->deleteArgs);
$service->handle();
The variables are all read here and passed in to help decouple the systems - doing it this way allows us to initialise the Service with different incoming variables and/or a different library which can be really useful when testing, as it allows isolation of individual components. The syntax for getting the put and delete data is an interesting one, I wrote about this already in my post on accessing incoming PUT data from PHP, there are some helpful comments on that post as well.
To be continued ... later parts will cover the service itself and the response format used.
Wrapping an Existing Class
The main functionality of the service was written in a class that had no awareness that it was a service - this is a similar approach to the one I described when I wrote about the PHP Soap Server - start with a normal functioning class and write some unit tests for it. The example I'm using today looks like this (my real version actually connects to the database and stuff but this is a nice mock of passing in a number and getting back an array):
class Library {
public function getUserDetails($user_id) {
$details = array(
"user_id" => $user_id,
"name" => 'Joe Bloggs',
"email" => 'joe@example.com');
return $details;
}
}
In the soap article, you can see that wrapping a class takes just a few lines - for REST more code is required, but the idea is completely the same. In actual fact we started out with this as a soap service but then it was switched to rest - I only had to re-write the wrapper stuff and not any of the core functionality. Using the wrapper approach would also allow services to be published in multiple ways with the same underlying codebase.
Incoming Requests - Intialising the Wrapper
First of all I wrote a .htaccess file to direct all requests to the one controller file - so that all the different URLs would be handled in the same way.
As the requests came into here, I grabbed the data I needed and initialised the service class, something like this:
$service = new Rest_Service();
// instantiate the main functional class and pass to service
$library = new Library();
$service->setLibrary($library);
// create a response object and pass to service
$response = new Response();
$service->setResponse($response);
// set up some useful variables
$service->url = $_SERVER['REQUEST_URI'];
$service->method = $_SERVER['REQUEST_METHOD'];
$service->getArgs = $_GET;
$service->postArgs = $_POST;
parse_str(file_get_contents('php://input'), $service->putArgs);
parse_str(file_get_contents('php://input'), $service->deleteArgs);
$service->handle();
The variables are all read here and passed in to help decouple the systems - doing it this way allows us to initialise the Service with different incoming variables and/or a different library which can be really useful when testing, as it allows isolation of individual components. The syntax for getting the put and delete data is an interesting one, I wrote about this already in my post on accessing incoming PUT data from PHP, there are some helpful comments on that post as well.
To be continued ... later parts will cover the service itself and the response format used.
PHPNW Site and Call for Papers Launched
Thursday, August 21. 2008
Yay! The PHPNW site is now online with all the details of the PHP North West Conference to be held on November 22nd, 2008 in Manchester, UK. The conference is specific to PHP and aims to develop the skills of the developers in the local area. Look out for local speakers, some drinking, and generally a good crowd. Put the date in your diary, tickets will go on sale soon.
We're also launching the call for papers for this event - it runs til 21st September and I'm really hoping we'll see some good entries covering a wide range of topics. We are including some shorter slots as well as the traditional 1-hour presentations, so hopefully you can think of something you'd like to talk about for one of those units of time.
If you've got any comments or questions about the event, the talks, submitting a paper or anything else PHP-north-west-y, then add a comment or drop me a line.
We're also launching the call for papers for this event - it runs til 21st September and I'm really hoping we'll see some good entries covering a wide range of topics. We are including some shorter slots as well as the traditional 1-hour presentations, so hopefully you can think of something you'd like to talk about for one of those units of time.
If you've got any comments or questions about the event, the talks, submitting a paper or anything else PHP-north-west-y, then add a comment or drop me a line.
PHPNW 2008 - 22nd November
Wednesday, August 6. 2008
The event is aimed at people working with, or wanting to work with, PHP in the north of England. We'll have a selection of sessions, with the technical content intended to be accessible to a whole range of audiences - it will also be multi-track so there's sure to be plenty of material to interest you, whatever your background. We will be having a call for papers for the sessions, and we're hoping that we'll get some good submissions - particularly from senior developers around the area and the wider UK. Whether you're hoping to speak, hoping to learn, looking for a good crowd to mingle with on a Saturday, or you just really like PHP geeks - put 22nd November in your diary and I hope I'll see you there!!
If you have any questions, comments or suggestions about this event, just let me know (I'm not organising the whole thing but I'm helping!), either by leaving a comment or by contacting me directly.
Accessing Incoming PUT Data from PHP
Wednesday, July 30. 2008
Recently I started writing a REST service. I began in the usual way, writing a php script, calling it with a GET request, accessing the variables using the PHP superglobal variable $_GET. I wrote code to handle a POST request and used the variables I found in $_POST. Then I tried to write a PUT request.
PHP doesn't have a built-in way to do this, and at first I was a little confused as to how I could reach this information. It turns out that this can be read from the incoming stream to PHP, php://input.
The above line provided me with a query string similar to what you might see on the URL with a GET request. key/value pairs separated by question marks. I was rescued from attempting to parse this monster with a regex by someone pointing out to me that parse_str() is intended for this purpose (seriously, I write a lot of PHP, I don't know how I miss these things but its always fun when I do "discover" them) - it takes a query string and parses out the variables. Look out for a major health warning on str_parse() - by default it will create all the variables all over your local scope!! Pass in the second parameter though and it will put them in there as an associatvive array instead - I'd strongly recommend this approach and I've used it here with my $post_vars variable.
This loads the variable $post_vars with the associative array of variables just like you'd expect to see from a GET request.
Its a bit of a contrived example but it shows use of the REQUEST_METHOD setting from the $_SERVER variable to figure out when we need to grab the post vars. Firstly, here's the script:
if($_SERVER['REQUEST_METHOD'] == 'GET') {
echo "this is a get request\n";
echo $_GET['fruit']." is the fruit\n";
echo "I want ".$_GET['quantity']." of them\n\n";
} elseif($_SERVER['REQUEST_METHOD'] == 'PUT') {
echo "this is a put request\n";
parse_str(file_get_contents("php://input"),$post_vars);
echo $post_vars['fruit']." is the fruit\n";
echo "I want ".$post_vars['quantity']." of them\n\n";
}
And here's what happened when I request the same script using two different HTTP verbs. I'm using cURL to show the example simply because I think it shows it best.
Via GET:
curl "http://localhost/rest_fruit.php?quantity=2&fruit=plum"
this is a get request
plum is the fruit
I want 2 of them
Via PUT:
curl -X PUT http://localhost/rest_fruit.php -d fruit=orange -d quantity=4
this is a put request
orange is the fruit
I want 4 of them
Purists will tell me that I shouldn't be returning data from a PUT request, and they'd be right! But this does show how to access the incoming variables and detect which verb was being used. If you're going to write a REST service then the correct naming of resources and the correct response to each resource being accessed in various ways is really important, but its a story I'll save for another day. If you use this, or perhaps you access the variables another way, then do post a comment - there aren't a lot of resources available on this topic for PHP.
PHP doesn't have a built-in way to do this, and at first I was a little confused as to how I could reach this information. It turns out that this can be read from the incoming stream to PHP, php://input.
The above line provided me with a query string similar to what you might see on the URL with a GET request. key/value pairs separated by question marks. I was rescued from attempting to parse this monster with a regex by someone pointing out to me that parse_str() is intended for this purpose (seriously, I write a lot of PHP, I don't know how I miss these things but its always fun when I do "discover" them) - it takes a query string and parses out the variables. Look out for a major health warning on str_parse() - by default it will create all the variables all over your local scope!! Pass in the second parameter though and it will put them in there as an associatvive array instead - I'd strongly recommend this approach and I've used it here with my $post_vars variable.
This loads the variable $post_vars with the associative array of variables just like you'd expect to see from a GET request.
Simple Example
Its a bit of a contrived example but it shows use of the REQUEST_METHOD setting from the $_SERVER variable to figure out when we need to grab the post vars. Firstly, here's the script:
if($_SERVER['REQUEST_METHOD'] == 'GET') {
echo "this is a get request\n";
echo $_GET['fruit']." is the fruit\n";
echo "I want ".$_GET['quantity']." of them\n\n";
} elseif($_SERVER['REQUEST_METHOD'] == 'PUT') {
echo "this is a put request\n";
parse_str(file_get_contents("php://input"),$post_vars);
echo $post_vars['fruit']." is the fruit\n";
echo "I want ".$post_vars['quantity']." of them\n\n";
}
And here's what happened when I request the same script using two different HTTP verbs. I'm using cURL to show the example simply because I think it shows it best.
Via GET:
curl "http://localhost/rest_fruit.php?quantity=2&fruit=plum"
this is a get request
plum is the fruit
I want 2 of them
Via PUT:
curl -X PUT http://localhost/rest_fruit.php -d fruit=orange -d quantity=4
this is a put request
orange is the fruit
I want 4 of them
Purists will tell me that I shouldn't be returning data from a PUT request, and they'd be right! But this does show how to access the incoming variables and detect which verb was being used. If you're going to write a REST service then the correct naming of resources and the correct response to each resource being accessed in various ways is really important, but its a story I'll save for another day. If you use this, or perhaps you access the variables another way, then do post a comment - there aren't a lot of resources available on this topic for PHP.
Ibuildings Seminar, Leeds
Friday, July 25. 2008
I'm happy to announce that Ibuildings is venturing north of the Watford Gap - and the next event will be in Leeds, on the 9th September, the full details are at http://www.ibuildings.com/events/leeds. The main tutorial session will cover source control with Subversion, including advanced concepts such as merging and repository structures. We'll also look at deployment strategies for different types of software development processes and tools that can be helpful in this area. I'm delivering the main tutorial at this event, and if that wasn't enough incentive, I'm also bringing the nabaztag as my glamourous assistant!
We'll be running events in a lot of other areas of the UK as well, so if you can't make this one then watch out for more announcements or tell us where we should be running the next one! If you have any queries about any of these events then feel free to contact me, I hope I'll see some of you in Leeds in September.
DPC Interview
Tuesday, June 24. 2008
So, at the Dutch PHP Conference, they were making a video and they interviewed me. The video is at http://www.bachelor-ict.nl/dpc and it is also featured in this article on DevZone which is exciting! The video is mostly about the PHPWomen organisation, rather than my talk but it does have some footage of me speaking and of the conference itself.
« previous page
(Page 3 of 7, totaling 38 entries)
» next page



Comments
Fri, 21.11.2008 07:43
I love your advice. I always wanted to surf the web without having to use a mouse. I use OPERA most of the time. I just didn’t know about that spatial navigation feature. Thanks a lot
Tue, 18.11.2008 15:11
I’m sure you’ll have no problem adjusting to that environmen t ;) Good luck on the talk.
Tue, 18.11.2008 08:42
wow! i see you like it as if it’s your pet!))) that’s great i wanna say! г can call him or her Acy as i do)))
Mon, 17.11.2008 22:31
Hey Lorna. Nice guide, though it did take me a bit to fig ure out which parts went in which classes. Just wanted to mention that you have a small mistake in your code: $this- >getVars[‘user_id’]) should be $this->getArgs[‘user_id’]) Since that’s what you defined in part 1 of the ser [...]
Mon, 17.11.2008 17:43
Stefan: Either the museum or a very long English Sunday Lunc h is on my agenda I think …
Fri, 14.11.2008 17:51
Thanks! I put in a trackback here: http://www.westwideweb.co m/wp/2008/11/14/grep-unknown-directories-method/ This hel ped me out of a jam today, thanks again, MXWest
Fri, 14.11.2008 10:48
hey! i have also Acer aspire and also have problems with cam era. it’s built in but this Acer Orbi Cam failed to work aft er a month…. don’t know what to do….
Fri, 14.11.2008 08:19
That museum looks excellent, might be a good pastime for sun day :)
Thu, 13.11.2008 10:36
The thing that gets me is this: in any non-trivial project, a model doesn’t just interact with MySQL. Models end up in caching layers, in sessions, and interacting with users thro ugh forms, query parameters, and of course APIs. Given al l that, any sort of model that is designed around tabl [...]