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 4 of 8, totaling 44 entries)
» next page


Comments
Mon, 05.01.2009 13:06
Doh! Interesting that you play piano, didn’t know that pi ece!
Mon, 05.01.2009 10:46
Daniel: I completely agree. I do like and use Zend Framewor k, but I already have books about it. When I buy a book on a subject, I don’t really want lots of ZF content. I can on ly assume that because its seen as a “buzz word”, people fee l the need to include it in any books current being wr [...]
Mon, 05.01.2009 10:41
Ubuntu User, Prasad, Joe – I’m pleased this was helpful, tha nks so much for dropping by and letting me know it worked ou t for you :)
Sun, 04.01.2009 23:25
Thanks for the tagging :) I responded (first time ever): htt p://www.urbanwide.com/2009/01/05/7-things/
Sun, 04.01.2009 06:42
You are my freakin’ hero! Thank you soooo much! mainMem.useN amedFile=FALSE fixed all my problems, my wife came back, I w on the lottery….. :) Thanks! Joe
Fri, 02.01.2009 23:33
I agree with your issues about some of the book turning into a mini ZF tutorial book. I feel that lately a lot of spa ce has been wasted on PHP books re-explaining MVC concepts, THEN introducing ZF (or another framework). Chalk it up to p ublishers not wanting to assume everyone reading the b [...]
Fri, 02.01.2009 00:44
All the best for Peru, and the rest of 2009!
Thu, 01.01.2009 23:33
Berry__: For normal people that is probably true but I add all sorts of clues which are different per-server, and still find myself regularly confused about which machine I’m logg ed in to …
Tue, 30.12.2008 15:23
Although I kinda like the colors for tabs, I think it’s over kill to have different colors on different servers. To be ho unest, I think the name of the machine you’re working on (on the left) is clear enough when working with it. The only thing I tend to dislike in screen, is that it’s rathe [...]