[Catalyst-commits] r7201 - trunk/examples/CatalystAdvent/root/2007/pen

jshirley at dev.catalyst.perl.org jshirley at dev.catalyst.perl.org
Sun Dec 2 17:27:11 GMT 2007


Author: jshirley
Date: 2007-12-02 17:27:10 +0000 (Sun, 02 Dec 2007)
New Revision: 7201

Modified:
   trunk/examples/CatalystAdvent/root/2007/pen/2.pod
Log:
Rest of the REST article

Modified: trunk/examples/CatalystAdvent/root/2007/pen/2.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/2.pod	2007-12-02 17:26:05 UTC (rev 7200)
+++ trunk/examples/CatalystAdvent/root/2007/pen/2.pod	2007-12-02 17:27:10 UTC (rev 7201)
@@ -1,57 +1,108 @@
-=head1 Dat 2.  Get more REST - Using YUI and JavaScript for REST
+=head1 Get more REST - Using YUI and JavaScript for REST
 
-Today, we'll look into building a fully capable REST client in YUI that allows
-record creation, retrieving, updating and deletion (CRUD) as well as searching.
+Today, we'll look into building a fully capable REST client in YUI that allows record
+creation, retrieving, updating and deletion (CRUD) as well as searching.  This is not a 
+copy and paste article, but explains the general concepts as a read-along to reading the
+source of the example application.
 
-=head2 Start Here First
+=head2 Start Here First: Understanding REST
 
-To make the most of this article, it is important to not only understand the
-basic idea of REST but to also see how it works within Catalyst.
+To make the most of this article, it is important to not only understand the basic idea of
+REST but to also see how it works within Catalyst.
 
-To start out understanding REST, read the excellent article by Ryan Tomayko 
-L<http://tomayko.com/articles/2004/12/12/rest-to-my-wife>, about explaining
-REST in simple terms that a non technical person is able to understand.  It will
-help a technical person understand it even more.
+To start out understanding REST, read the excellent article by Ryan Tomayko
+L<http://tomayko.com/articles/2004/12/12/rest-to-my-wife>, about explaining REST in simple
+terms that a non technical person is able to understand.  It will help a technical person
+understand it even more.
 
-Up next is to get a good understanding for how REST works inside of Catalyst,
-using Adam Jacob's excellent L<Catalyst::Action::REST> package.  The best way
-to get up to speed is to review Day 9 from the 2006 Advent Calendar, at
-L<http://www.catalystframework.org/calendar/2006/9>.
+Up next is to get a good understanding for how REST works inside of Catalyst, using Adam
+Jacob's excellent L<Catalyst::Action::REST> package.  The best way to get up to speed is to
+review Day 9 from the 2006 Advent Calendar, at
+L<http://www.catalystframework.org/calendar/2006/9.pod>.
 
-=head2 Following Along
+=head2 Following Along: Using the Source
 
 The examples that are listed here are available from the Catalyst subversion
 repository, available via:
 
  svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/RestYUI
 
-It is a good idea to check out the sources of the sample application to better
-follow along with the examples.  Included is the necessary YUI javascript files
-to enhance this application as you go.
+This is a fully functional application that uses REST webservices instead of the
+traditional method of form submission and posting.  While this isn't an ideal use of
+REST, and it doesn't give you anything over a non-JavaScript based form, it should help
+people think about things a little different and show the power of a framework that can
+use any view, not just HTML, to represent objects.
 
-=head2 Why use JavaScript?
+This article talks about building the core pieces, but there are many other important
+points in the example application that are not covered specifically in the article.  Please
+check out the source above, run the application and read the source as you read this
+article.  
 
-The reason why we're required to use JavaScript for a full REST service is
-because of the limited vocabulary that a browser coupled with plain HTML is
-allowed to speak.  The browser will only ever send GET and POST requests in
-response to user interaction with an HTML document.  However, when using the
-C<XmlHttpRequest> method that is a standard in all Grade A browsers the 
-vocabulary is extended to support PUT, DELETE and HEAD.
+=head1 Why use JavaScript?
 
-=head2 The Connection to REST
+The big question that comes along when working with REST in the browser is why do you have
+to use JavaScript.  The reason why we're required to use JavaScript for a full REST service
+is because the vocabulary that a browser speaks natively is limited to only two verbs: GET
+and PoST.
 
-REST is based off of getting what you ask for.  In the simplest form, an
-C<XmlHttpRequest> isn't enough to talk to a REST webservice.  There are a few
-major components that fit together to make everything work:
+However, when using the C<XmlHttpRequest> JavaScript object that is available in all Grade
+A browsers the vocabulary is extended to support PUT, DELETE and HEAD and many others.
 
+With this, you can write a web application that is also a web service, with very little
+redundant code.  Additionally, the tests can test the data and separate tests can test
+the HTML rendering.  This makes things much less tedious, and the tests more accurate.
+
+With Selenium testing the JavaScript, you can have full end-to-end testing with very little
+pain.  To me, we're finally at a point in browser development where the question is why not
+use JavaScript.
+
+=head2 Connecting to REST
+
+The general idea of REST is getting what you ask for, in the format you want.  In the
+simplest form, an C<XmlHttpRequest> isn't enough to talk to a REST webservice.  There are a
+few major points that come together to make everything work:
+
 =over
 
 =item Content Type
 
+Because YUI assumes you're working with a brain-dead framework that can't
+support wonderful things like REST, you have to map the default content-type
+(or dig into YUI and setup different content type headers, but this is quite
+a bit of work).  In the REST controller, assigning this content type to 
+serialization format is a piece of cake:
+
+ __PACKAGE__->config(
+    # Set the default serialization to JSON
+    'default' => 'JSON',
+    'map' => {
+        # Remap x-www-form-urlencoded to use JSON for serialization
+        'application/x-www-form-urlencoded' => 'JSON',
+    },
+ );
+
+YUI will also not set the default content type header to a useful value, so you have to
+do that in the JavaScript.  This is covered later in detail.
+
 =item Request Method
 
-=item 
+The request method is the verb.  This means you are GETting a resource, PUTting a new
+resource in the system, POSTing an update to an existing resource or DELETEing something.
 
+Luckily, XmlHttpRequest and YUI supports this just fine without any additional tweaking.
+
+=item Data Serialization
+
+The Content-Type not only specifies how you want the data back, but it specifies how
+you are sending data.  In the context of a PUT or POST, any data you send has to match
+the Content-Type provided.  So if you send a Content-type header of 'text/x-json', the
+data has to be in JSON.  There are a ton of serialization formats available, so pick
+what works best for you in each application.
+
+If you're working with a JavaScript-based interface, I prefer JSON.  If I'm doing command
+line interaction, I like serialization in YAML.  The same resource can handle multiple
+serialization formats, just change the Content-type!
+
 =back
 
 =head2 Starting the Catalyst Application
@@ -75,8 +126,34 @@
 L<http://developer.yahoo.com/yui/>
 
 After extracting the files from the zip archive, just copy over the .js files to
-the root/static directory.
+the root/static directory.  My preferred method is to do this:
 
+ cd MyApp
+ mkdir root/static/yui
+ cd /where/you/unpacked/yui/build
+ for i in *; do cp $i/$i.js $i/$i-beta.js /path/to/MyApp/root/static/yui; done
+
+That will copy all the non-minimized (but not debug versions) and beta JS files
+into your static/yui path, so you can reference them with an easy URI:
+ C</static/yui/yahoo.js>
+
+The other files that are very useful are the "sam" CSS and image files.  For
+the datatable, we're going to use C<sam/datatable.css> and a few other images:
+
+=over
+
+=item sprite.png
+
+=item dt-arrow-dn.png
+
+=item dt-arrow-up.png
+
+=back
+
+Those will make the DataTable look nice and stylish.  If you want to expand more
+on the YUI styles then the buttons, containers and other layouts are a great
+asset provided by Yahoo.
+
 =head2 Preparing the REST WebService
 
 To gain access to the REST services, we'll be accessing both the C<list> and the
@@ -177,8 +254,100 @@
             }
         );
 
-=cut
+=head1 Adding REST PUT and POST Methods via YUI
 
+The fundamental difference between a PUT and POST is a PUT creates a new resource and
+POST updates an existing resource.  In the original advent article, the PUT and POST
+articles were aliased and therefore provide identical functionality.  We're not going to
+change this, because for the purposes of this article it doesn't matter.  YUI will
+respect whatever method provided in the C<asyncRequest> call.  So if you want to do a
+PUT, the call looks like:
+
+    var request = YAHOO.util.Connect.asyncRequest(
+        'PUT',
+        uri, callback, json_data
+    );
+
+It's a good idea to read the overview and some examples of how to use asyncRequest, but
+the usage is very simple.  That is really all that is necessary to trigger a REST call
+in YUI, but you have to watch the content type.  By default, YUI will not set the
+proper content type, and since JSON is by far the easiest serialization method to use
+in JavaScript, we're going to use that.  YUI fortunately has an easy method for changing
+the content type, but it isn't a well-named method and you have to be careful because it
+sets the content type on subsequent calls:
+
+    YAHOO.util.Connect.setDefaultPostHeader('text/x-json');
+
+Adding that line before any C<asyncRequest> calls will ensure you are sending the
+right content type header, and won't cause the REST service any confusion.  The next
+step is actually encoding the JSON data from the form.
+
+=head2 JSON Parsing and Encoding in JavaScript
+
+The C<json2.js> JSON stringifier and parser is used in this article and is available from
+L<http://www.JSON.org/js.html>.  It is public domain, and works very well.
+
+=head2 From Form to JSON to REST
+
+Given a form object, as what is declared in the C<root/user/single_user.tt> file, and
+hijack the normal submit mechanisms to enable a REST POST or PUT to a backend webservice
+is just a simple few lines of JavaScript:
+
+    /* Setup the listener when the form is submitted: */
+    YAHOO.util.Event.addListener(form, "submit", function(e) {
+        /* Cancel the default submit event.
+           You can get creative here for graceful fallbacks, think about it!
+        */
+        YAHOO.util.Event.preventDefault(e);
+        /* Start a timeout to encapsulate the REST call */
+        window.setTimeout(function() {
+            /* What URI are we going to POST or PUT to?  Ourselves, in this case */
+            var uri  = '[% c.req.uri %]';
+
+            /* The actual data structure, it still is just JavaScript at this point.
+               Keep in mind there are better ways to take a form and translate it into
+               JSON, but being explicit never killed anybody
+            */
+            var data = {
+                user_id:     form['user_id'].value,
+                fullname:    form['fullname'].value,
+                description: form['description'].value
+            };
+            /* Set the content-type to text/x-json, otherwise things will break! */ 
+            YAHOO.util.Connect.setDefaultPostHeader('text/x-json');
+            /* The actual call, this bit makes the HTTP call */
+            var request = YAHOO.util.Connect.asyncRequest(
+                '[% method %]',
+                uri,
+                /* Callback should contain a success and failure method, read the
+                   YUI asyncRequest docs! */
+                callback,
+                /* Stringify our data structure into JSON, this is sent in the HTTP BODY */
+                JSON.stringify(data)
+            );
+        }, 200);
+    });
+
+That's it, with a lot of comments!  This will send a PUT or POST request to the backend
+service with the form data encoded in JSON.  You're not limited to PUT or POST methods,
+you can also use DELETE, HEAD and any other method defined in the RFC.
+
+To see the full page, check out C<root/user/single_user.tt> in the RestYUI example.
+
+=head1 The State of (un)REST in the Browser World
+
+Beware, that not all browsers support every method so YUI and REST is not guaranteed to
+work on every browser and every platform.  It's up to the browser developers to decide to
+support full specifications and I'm happy to report that most browsers do in this context,
+including both Internet Explorer 6.x and 7.
+
 =head1 AUTHOR
 
-J. Shirley
+J. Shirley wrote the YUI based portions, with the original 2006 REST article
+being written by Adam Jacob.
+
+Adam Jacob also wrote the Catalyst::Action::REST module, which is the foundation
+to all of this.
+
+=cut
+




More information about the Catalyst-commits mailing list