REST with the Recess! Framework
Submitted by Matthew Turland on Wed, 01/28/2009 - 09:45Some people might immediately dismiss this post based on its title. The immediate response of others is likely to be a groan immediately followed by, "Not another framework!" Were this yet another general purpose PHP framework for web applications, I would agree. It's already obvious we have more than enough of those, whether they're aimed at general web development or content management.
But this framework has a different focus, at least partly outside of those two areas. REST is an set of architectural principles and concepts often applied (though not limited) to web service implementations. The focus of REST is resources (things) and a simple set of operations (similar to those included in CRUD) that can be performed on resources.
Ben Ramsey has presented and written about REST a great deal in the past. The April 2008 issue of php|architect magazine has an article on the subject; if you don't have that issue, you can look forward to another article that Ben has written for the upcoming February 2009 issue. You can also find a few articles on the C7Y PHP Community web site. So given all this background information on REST that I'd seen thus far, I decided to dig a little deeper into the Recess! Framework after coming across mention of it across several blog posts.
There were a few things that troubled me about the project going in. First, while the main project web site has a development blog and discussion forums, and the author has written several blog posts about the framework, there are no official tutorials or documentation to speak of at the time of this writing. Thankfully, the README file bundled with the preview release indicates that these are top priorities for the next version. A tool or library may indeed be the best thing since sliced bread, but prospective adopters will only put forth so much time and effort to figure out how to use it before moving onto an alternative. It's in the best interest of the project to make it as simple as possible (but no simpler) for people to pick it up.
Second is that the components included in the framework indicate a scattered focus. An MVC stack, a PDO-based DAL, an ORM system, a scaffolding system, multiple caching backends -- these are all things that plenty of existing frameworks, RAD or not, have already. While its routing mechanisms have been the subject of some examination, they're not overly dissimilar from routing mechanisms in other frameworks. Same with wrapper classes for requests and responses.
Smarty is bundled in the preview release, but the landing page on the project web site states that both Smarty and native PHP views are supported. It would seem more natural to not to bundle Smarty and allow the developer to include if it it's being used. Same with SimpleTest: if I want to run the unit tests, I'll download it and point the test runner to it myself. I also have to question why Smarty would be useful as a view layer for this particular application domain. Most use cases I see for Smarty involve either a team of web designers already familiar with it or systems in which users can manipulate templates (for security reasons), but not a REST API.
Third is the organization of the code itself. Multiple adapters for things like caching and views are bundled into single files or included whether they're needed or not. While I've said I don't entirely agree with views that statics are evil, the Recess! code makes rather liberal use of them. Tickets #51 and #54, which I filed, make me wonder if the development team uses an E_STRICT level of error reporting (which I very much hope you're doing in your own code). Given that tickets haven't been updated in a month or so, mine may have been filed in vain.
The post probably sounds like a rant at this point. Really, the major frameworks already have most of the components that a REST application would use and just need a little augmentation to be more REST-friendly. Here are a few points to that end.
- Modification of the application response to indicate to the client that the response data can be cached and for how long. This reduces demands on the server because the client can used the cached response for a time rather than having to request it from the server again. Server-side caching has its place but the less traffic that the server has to handle, the better.
- Support for multiple representations of each resource. Ideally, all resources should have a unique canonical URL from which they can always be accessed and their representation format determined using content negotiation. This includes the content format (HTML, XML, JSON, Atom, etc.), language (English, French, Spanish, etc.), and character set (ISO-8859-1, UTF-8, etc.). So long as this is maintained, it is acceptable to also offer other URLs specific to particular representations of a given resource. (Twitter does this.)
- Declaration of which methods (GET, HEAD, POST, PUT, DELETE) each offered resource supports, as not all resources may support all methods, and a mechanism to return an appropriate HTTP response (405 Method Not Allowed) if a resource is accessed using an unsupported method. Responses should include an Allow header indicating supported methods, especially in 405 responses but ideally for HEAD requests as well.
- Support for documentation generation from REST service source code. Ideally, this would come in the form of a service browser that offered full explanations of each resource including available representations and methods, possibly with WSDL 2.0 support.
- Content encoding (gzip, deflate) should be supported in both directions. That is, a client should be able to submit data that is encoded and the server should be able to encode content when the client requests it.
In the end, if your application is carefully thought out and well-designed, adding a REST API should be borderline trivial because only the resource representation should change to be more appropriate for automated agents to consume it. I hope to see more developments toward REST-friendless in the major frameworks in their future versions.


Appreciate the Thorough Investigation
Nice to meet you
Nice to make your acquaintance, Kris.
1) I hear you: it does tend to be difficult to keep up with documentation, especially on larger projects. Glad to know you're working on that, though.
2) Good to know that you're aiming for loose coupling, though I'm still admittedly unconvinced that development of these components is necessary given the current offerings available to fulfill their intended purposes. It seems like your time would be better spent working on the parts of the framework that aren't already present elsewhere rather than reinventing the wheel.
3) Caching is fundamental, yes, but see my response to #2. There are caching backends in other frameworks as well as independent components in libraries like PEAR. As far as breaking the one class per file convention, see point #3 in this blog post and the Appendix section it inspired in the ZF documentation. Your attempt seems to be in the vein of premature optimization to me, but if you think it's a valid concern, you may want to investigate this technique.
I do hope that Recess goes on to become as well known as the other frameworks I've linked to in my original post, though I'm skeptical as to whether it will do so unless it introduces value that isn't present elsewhere. Good luck and best wishes in your endeavors to bring that to the PHP community.
Regards,
Matt
Good overview
Re: OPTIONS
Nate,
You're technically correct about OPTIONS. To quote RFC 2616 Section 9.2, "A 200 response SHOULD include any header fields that indicate optional features implemented by the server and applicable to that resource (e.g., Allow)." However, the RFC also mentions a few other things that are pertinent.
If a Max-Forwards header is included in the request, it's possible that it will only go so far as to reach a proxy server, rather than the origin server hosting the originally requested resource, and that the returned response will reflect information about that proxy.
If the request does return the resource, the presence and format of the response body is not defined by the RFC. It might be the resource content depending on the server implementation, which is not ideal if it's large and/or not needed by the client. That's why I recommended a HEAD request, because its response is cacheable and it never returns a response body.
Hope that clarifies my explanation. Thanks for your comments.
Regards,
Matt