Using REST internally within an application
Monday, September 29th, 2008I’m a total REST fanboi. It’s at the very core of “the web” and it’s a great way to open up a webservice fairly easily (and in a way that can be consumed easily).
I’ve recently been working on a web-app where the UI could make use of AJAX to increase the usability; but I’ve been a little hamstrung by my approach to my “controllers”. When I want to do something via AJAX then I find myself creating a specific route for that request, which means I kind of duplicate some of my logic (and it’s a pain to write extra code).
Take “in-page pagination” as an example. My app displays a table of people when /people is requested, along with all the rest of the markup for that page (navigation, panels of other data etc). When the user wants to view the 2nd page they click on “next” which takes them to /people?page=2, and another table of data. To AJAX things up, I want to fire off an XmlHttpRequest when they click “next” which brings back a JSON string of “page 2 data”, which I can dynamically inject into the page. If I call /people?page=2 via AJAX, then I incurr the overhead of generating “all the other panels/markup” as well as it returning a full HTML page, rather than a nice JSON string; my workaround is to create a new route, /people/ajax, which returns just a JSON string. That’s pretty sucky when you scale that up to even a small “real world” application.
What would be cool is if I could automatically expose my “data mapper” (database) CRUD methods via HTTP. So instead of making a new Action for “/people/ajax” that essentially wraps a call to $db->getPeople() and then json_encodes the recordset, I could directly call getPeople() via AJAX. Hmn… I’m sure there’s a technology somewhere that would be appropriate for that! ;).
So my idea is to use REST as layer on top of my application’s data. That’s nothing new, it’s called “a webservice!” but what if we extend it to also completely wrap the data-layer from the internal application? So the only way to receive or update any data is by going through the REST interface, kinda like consuming your own internal webservice. Think of it like running 2 servers, a REST-server and a web-server (where your normal application lives). Your “application code” has to issue HTTP requests to the REST server in order to get data or to update records.
So why do this? Well firstly it (probably) makes your entire application inherently RESTful, which helps solve my AJAX example. If you’ve already got something at the REST-server level that returns data when you call “GET /people?page=2″, then you immediately have access to that same data “webservice” from inside the browser: no need for extra controllers or forking a controller based on an “X-Requested-With” header. This is also true for “normal webservices” - you immediately have webservices available for anyone else to consume (obviously, subject to your security considerations). I think this approach might also help with caching: if all data requests go through the REST-server then it provides an abstraction for the caching (your “HTTP-client” just caches requests using normal HTTP caching principals). It also locks the data-layer away from your junior developers
(and helps teach them REST!). I haven’t thought much about it, but it might help mask other scaling issues: the client, your app, just connects to the REST-server, which worries about the multiple backend MySQL or Memcached servers and external webservices. Maybe it also gives you a unified log of all data operations (by logging the “HTTP request”) regardless of where the actual data it stored? Anyways, I think there are some nice reasons why this architecture might be pretty cool.
Now you might be thinking, “Dude, this is gunna suck! An HTTP request is going to be much slower than my normal mysql_query()!”. And you’re probably right - in that extra layers of abstraction tend to have a speed hit. But depending how it was implemented, It might not be much at all, and dare I say give better performance than some of the “PHP ORM” libraries? Firstly, the HTTP request is at worst going be on the same local network, probably on the same local machine (perhaps a unix socket?), and at best not via any IPC at all - you could interface directly with the “REST-server” if that “server” was some PHP code (thought this perhaps defeats some of the benefits of a client/server architecture).
Actually thinking a little more about it, I don’t think the overhead would be much at all. Memcached/MySQL/CouchDB etc are often distributed over multiple machines. CouchDB is very relevant to this idea, as they make data accessible via an HTTP/JSON interface. This gives an overview of how PHP and CouchDB can work together and is conceptually similar to how I’d see a “REST data layer” working.
When I get some free time (:() I’m going to explore this idea some more :).