Building a RESTful PHP Server: Output Handlers
Output Handlers Instead of Views
We’ll have as many output handlers as we have supported output formats. The joy of having all the controllers return the data to index.php
is that we can then add common output handling to all the data. In our example system, we can remove that ugly print_r
from index.php
and instead detect which output format is needed and load the relevant view. My code looks like this:
$view_name = ucfirst($request->format) . 'View';
if(class_exists($view_name)) {
$view = new $view_name();
$view->render($result);
}
The most simple example is a JsonView
which looks like this:
class JsonView extends ApiView {
public function render($content) {
header('Content-Type: application/json; charset=utf8');
echo json_encode($content);
return true;
}
}
As you can see here, it’s pretty simple! We send the Content-Type
header first to let the consumer know what’s in the response, then we just encode the JSON and echo it out.
To support other formats, you might loop over your array (remember it might be nested – things usually get recursive at this point for something like an XML format) and transform it into the new format. Between two PHP systems, it might be simpler to support serialised PHP as a format as it is a little more verbose than the JSON.
I also like to support HTML as an output format – for example the joind.in API does this; just go to http://api.joind.in with your browser and it will realise you’re a web browser and return you the HTML version. Joind.in is open source and since I wrote its RESTful API, it looks a lot like this one! You can see the HTML output handler at: https://github.com/joindin/joind.in/blob/master/src/api-v2/views/HtmlView.php
One format that I often get asked about is JSONP – so that other sites can make calls to the API from JavaScript and get around the cross-domain policy. The way that I’ve implemented this in the past is to check for a parameter called “callback” with a request for JSON format, and if I get it, then just wrap the function around the response I would normally send. I blogged about it here and again, this feature is in joind.in’s codebase if you want to take a look.
Along with the data from the controller, it can also be useful to add some additional information to your output handlers, such as a count of how many top-level records were returned, and sometimes some pagination (I think I could write a whole other post about hypermedia and pagination – if you want it, leave me a comment). This additional functionality should be added in the parent ApiView
class – this just has a few helper functions which the various output formats can use if they want to. Having it all central means that the responses will be very consistent across all the requests made to this service, and between formats. Consistency is absolutely the key to a good API so more shared functionality is always good.
There you have it, one functioning RESTful (ish! we skated over a few issues here, read the comments on all the posts in the series) server. You can test it by calling your service from cURL or writing a script to consume it from PHP instead. Since this was a simple tutorial there are some areas where I’d have liked to have gone in to more detail but it is already quite long-winded, so I’ll stop there and if I get any good questions in the comments, I may add some followup posts!
Pingback: Building A RESTful PHP Server: Routing the Request | LornaJane
Pingback: Building a RESTful PHP Server: Output Handlers | LornaJane | PHP Web Development | Scoop.it
Pingback: Lorna Mitchell’s Blog: Building A RESTful PHP Server: Output Handlers | Scripting4You Blog
Pingback: Building a RESTful PHP Server: Output Handlers | LornaJane | v3k.net | Scoop.it
Pingback: Building a RESTful PHP Server: Output Handlers | LornaJane | Next Web App | Scoop.it
Lorna,
I’ve not used MVC pattern before so I’m still struggling with it a bit. Is there a source code the the sample somewhere I can download and play with.
Thanks for the great tutorial.
JB
The best MVC tutorial I’ve ever seen is Rasmus’ – it’s what I use to teach this pattern in my OOP and Design Patterns courses, I actually have my attendees build an MVC app with no framework. You can read the post here: http://toys.lerdorf.com/archives/38-The-no-framework-PHP-MVC-framework.html
where I can get the full example code?
I’ll upload it somewhere for you … watch this space
OK , thanks!
Any update on the availability of a ZIP of all these files, ready to go?
I’m interested in the full code as well. It seemed to me that there was something missing. So I added the following to create a Request Object instance, and populate the $url_elements array:
$ro = new Request;
$url_elements = $ro->url_elements;
But still, something is wrong for me. Admittedly, I’m operating on very little sleep, and it might be obvious, but I don’t think my version can see the “UsersController” class.
Hmmm, I think the issue that I’m dealing with is the base class: myController. I don’t see where that’s defined. Did I miss it?
For what it’s worth, I got mine working, although there were several issues I found:
1. My system doesn’t know what __DIR__ is. I substitute “dirname(__FILE__)” in the include function
2. I created base classes for MyController and ApiView and included them before I pulled in the extended classes
3. A bug I found in your code is in UsersController::getAction() there is a switch statement that doesn’t have a closing curly bracket.
Also, thanks for the Tut! I’m not trying to be negative, just scratching my head on a few details there. Great stuff!
Thanks for the kind words, hopefully now the whole code is posted it will make more sense. Or, more likely, you already solved the issues :)
Hello Denvermatt,
Could you please provide the code that you used for #2? I would very much appreciate it. I also hope i am not too late, hopefully you have not deleted the files… :)
Kind Regards,
Rey
Have you the whole code somewhere?
LOTS of people asked me for the code, and I’m sorry it took me a while to upload it. You can find it on bitbucket: https://bitbucket.org/lornajane/restful-php-examples (just look for the “get source” button over on the right if you don’t want to clone the repo). Hope that helps and answers some questions where I didn’t have the full code in the blog posts.
Many thanks for all your comments, it’s great to get some feedback!
Thank you!
Thanks a lot ! It’s even more clear now :)
Thanks a lot for tutorial ;)
Pingback: Adding Custom Headers to Every Request with Chrome | LornaJane
I’ve been playing around a bit with your code here but can’t get it to work even when i download your source code and try to run it.
All i get is a few php warnings when i try to run it.
Warning: include(/Applications/XAMPP/xamppfiles/htdocs/restfulphp/library/Controller.php) [function.include]: failed to open stream: No such file or directory in /Applications/XAMPP/xamppfiles/htdocs/restfulphp/index.php on line 16
Warning: include() [function.include]: Failed opening ‘/Applications/XAMPP/xamppfiles/htdocs/restfulphp/library/Controller.php’ for inclusion (include_path=’.:/Applications/XAMPP/xamppfiles/lib/php:/Applications/XAMPP/xamppfiles/lib/php/pear’) in /Applications/XAMPP/xamppfiles/htdocs/restfulphp/index.php on line 16
Am i missing something here? I even tried to include a few url elements but when i do that i just get an Object not found! page from apache.
I’m not sure what exactly is wrong there, PHP can’t find the files that are being included. This is likely to be related either to permissions, or to the fact that the autoloader makes assumptions about how the paths will work – so if I were you I’d start there for debugging. Good luck :)
I’m new to MVC and the RESTful model so I’ve read through the series and *think* I’m following it ok… I’m just not sure how to test the example. Do I need to send a JSON string as the body of a POST request to get anything back? Is there a simple way to test quickly (that it’s doing anything) from a browser with ? params?
Thanks again for your work..
I found my problem, but not sure what the specific issue is. the MyControllers class is not registered and therefore the UsersController class could not extend it. I tried manually including it at the top of index.php to no avail and ultimately dropped MyControllers and took out the “extends MyControllers” clause from UsersController.php.
(tail -f is your friend)
Are you working from the code in the posts or the downloaded example? I’m not sure the MyController class (and be careful whether it is plural or not) was declared in the examples, but the code I linked in the earlier comments should work. Good luck!
Hi, great posts! I’m interested to know if you have example code for the serialized php view you mention? Thanks! :)
I don’t have an example but you’d just make another view class that extends ApiView and sits alongside the other options. It would just need to serialize the data instead of json encoding it – and for a header you might send application/php but that’s not widely used so I’d also be happy to see text/plain given. Hope that helps
I come to this with some coding and design experience, but no PHP. Within a couple of hours my database was available by a RESTful api on a public site. Thanks very much!
Thanks so much! Great tutorial!
How should you call the example? ../?users or what?
Yes, make a GET request to /users to have it run the getAction in the UsersController.
Hi, great tutorial. I hate to ask, but could you post an example of hire the client calls the service ?
I know for experienced folds that’s elementary, but unfortunately I need to see it in order to pull it all together.
Thanks
From PHP I would call this by doing something like:
file_get_contents(“http://api.yourdomain.com/users”);
Hopefully that helps you get started!
Really appreciate you taking the time to write all this out. I know all to well how hard it is to come up with the time to put things up on the net for others, so I just wanted to drop you a line to tell you its appreciated!
I know there were some critical comments early on on one of the other pages, and validity of those comments aside, I think it’s in everyone’s best interest to take everything with a grain of salt, research lots of sources, compare, contrast and pick the best approach that works in their individual circumstances, I think this is particularly true in the context of REST :)
In the end yours and one other are the basis for the API I’ve just built, just in case it helps anyone else the other is here: http://www.gen-x-design.com/archives/create-a-rest-api-with-php/ and although it’s a bit aged at 2009, it was still a good starting point.
All the best, keep up the good work, and Cheers!
My pleasure, thank you very much for sharing in return :)
Hi! your work is highly appreciable. Actually, i am not a web developer by profession and was looking out on web how to create a POST restful web Service in PHP, and boom found it all on your page not only this but you also cleared my MVC in php concepts as well.
Thanks Lorna! Hats off for your efforts :)
Nice article ! I don’t see any htaccess in the source code you uploaded ( https://bitbucket.org/lornajane/restful-php-examples/src/643debe965e8?at=default ). Is it normal ?
I don’t usually use .htaccess in my projects, and this one doesn’t need anything extra configured to make it work