Python DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Using REST with Ajax
Pages: 1, 2, 3

Building a Web App on Top of the API

This is a pretty simple API, yet it models most of the things you need to do with a database of anything.



The trouble is, how do you get this into a browser? The GET is easy; a user can GET the list of feeds and maybe keep a bookmark to it so he can easily retrieve the list.

POST is also quite easy. I could have a page with a text box on it so that a user can submit a URL. In fact, I have a Greasemonkey script to find RSS or ATOM feeds in a page and ask the user to POST it to the feeds web app.

DELETE is the hard option to support, because browser web forms don't allow you to send a DELETE operation. This screws up the whole app. How can you allow users to remove feeds from their lists?

One way around this is to make a POST with a method identifier, so you have HTML like:

<form method="POST" action="/someuri">
<input type="hidden" name="method" value="DELETE"/>
</form>

This is all very good, but the trouble is you need to add specific code to your web app for handling this. It's just another thing to get wrong, and it still doesn't entirely fix the problem--submitting the form will always cause a context change. In other words, the server returns a page from the POST and the browser displays it.

There are ways around that, but they're all clunky. The most common is to return a redirect to the page from which the user submitted the pseudo-delete. That's more complicated code in the handler.

Here's Ajax

Here's where Ajax comes in. Use the XMLHttpRequest object of Ajax to send the DELETE to the server.

How do you do this? The list of feeds is the natural place to start. If the HTML version of the list of feeds allowed feeds to be deleted, then you could add some Ajax code to that page to perform deletes.

So as not to complicate things by adding XSLT, here is some straight HTML that the GET method might deliver:

<html>
<head>
<script>
<![CDATA[
// Delete any marked feeds
function delFeeds ()
{
  var feeds = document.getElementById("feeds");
  for (var i = 0; i < feeds.elements.length; i++)
   {
      if (feed.elements[i].checked)
      {
         var feed   = feeds.elements[i];
         var req    = new XMLHttpRequest();
         req.feedId = feed.id;

        function delHandler(evt)
        {
           if (evt.target.readyState == 4 && evt.target.status == 200)
           {
             var feedLabel = document.getElementById("feed_" + evt.target.feedId).style.display = "none";
             feed.checked = false;
           }
         }

         req.onload = delHandler;
         req.open("DELETE", "/feeds/" + req.feedId, true, "nic", "hello");
         req.send("");
       }
    }
}

]]>
</script>
</head>
<body>
<h1>Current feeds</h1>
<div id="feed_form">
    <form id="feeds" action="javascript:;">
        <label>Delete?</label>
        <label id="feed_1">
           <input type="checkbox" id="1" name="1" value="1"/>
           http://www.tapsellferrier.co.uk/nics-blog.xml
        </label>
        <label id="feed_2">
           <input type="checkbox" id="2" name="2" value="2"/>
           http://news.bbc.co.uk/rss/newsonline_uk_edition/technology/rss.xml
        </label>
        <label id="feed_3">
           <input type="checkbox" id="3" name="3" value="3"/>
           http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml
        </label>
        <button name="delete" onclick="delFeeds();">delete</button>
    </form>
</div>
</body>
</html>

This is an HTML form of three items, each with a check box. The idea is to allow a user to select all the items to be deleted and then press the delete button. It doesn't have to be this way, of course--you could have an onclick handler on each feed item to call the Ajax, but I prefer it this way.

Now it's pretty clear. The JavaScript sends the correct HTTP request to the REST API with simple DOM code.

There is one more point of interest here: synchronizing the user's view of the feeds list with the actual state of the feeds list on the back end. When a user deletes any feed, this view should update to reflect the deletion. How can you make that happen? The Ajax could easily cause a page refresh, and that would cause the display of the feed list to reflect the state in the database.

The trouble with a refresh is that it involves another network trip. For a simple edit, this is unnecessary. The browser knows what the user has removed. The code actually turns off the display of the item being deleted.

And Finally ...

I think that this is the right way to go with web apps. Ajax can be complicated, but REST makes it simpler. In turn, Ajax simplifies REST apps--or at least reduces the need for complicating them. By combining them, you get the best of both worlds.

Nic Ferrier is an independent software consultant specializing in web applications.


Return to the Python DevCenter.



Sponsored by: