---
title: 'Jester 1.1: Asynchronous REST'
teaser:
tags: news,web,javascript,jester
author: Eric Mill
published_on: 2007-04-16
---

Since [first releasing Jester][jester], we've gotten a fantastic amount of
interest and support, and even some donated code.  In response, I've been
whipping Jester into more powerful shape this week.  The syntax now even more
closely resembles [ActiveResource's][ares-syntax] and ActiveRecord's, and adds
the ability to use Jester asynchronously.

[jester]: https://thoughtbot.com/blog/jester-javascriptian-rest
[ares-syntax]: http://weblog.techno-weenie.net/2006/12/12/taking-ares-out-for-a-test-drive

Jester is available from SVN in [trunk form], or a [1.1 release] form. You can
also download a [zipped copy of 1.1].

[trunk form]: http://svn.thoughtbot.com/jester/trunk
[1.1 release]: http://svn.thoughtbot.com/jester/tags/rel-1.1/
[zipped copy of 1.1]: http://images.thoughtbot.com/ui/2007-4-16-jester-1.1.zip

Jester is released under the MIT License.

More completely, today's release of Jester 1.1 includes:

* Asynchronous support
* find('all'), find('first') – Works like ActiveRecord.
* attributes() – Works like ActiveRecord.
* reload() – Works like ActiveRecord.
* Pluralization, a proper Inflector library. (Thanks to [Ryan Schuft])
* Cleaned up and expanded JsUnit tests.
* Significant code cleanup and prettifying.

[Ryan Schuft]: https://code.google.com/archive/p/inflection-js/

To trigger **asynchronous** mode, a callback can be provided as an optional
ending argument to find, save, create, reload, and destroy.  This callback will
be passed as an onComplete option to Prototype, and will be called regardless of
success or failure.  The callback function will be passed the same return result
you'd expect if you had called the function synchronously.  The asynchronous
versions all return the underlying AJAX transport object, which in Firefox is an
XMLHttpRequest.

```javascript
>>> User.find(1, function(user) {eric = user})
GET http://localhost:3000/users/1.xml
XMLHttpRequest

>>> eric
Object _name=User _singular=user _plural=users
>>> eric.email = "beverly@cleary.com"
"beverly@cleary.com"

>>> eric.save(function(saved) {result = saved;})
POST http://localhost:3000/users/1.xml
XMLHttpRequest
>>> result
true

>>> User.find(eric.id).email
GET http://localhost:3000/users/1.xml
"beverly@cleary.com"
```

You can use **find('all')** to get an array of all objects, and
**find('first')** to perform this same find, but automatically return only the
first one.  These two calls perform the same request—find('first') simply
discards the rest of the array.  To me, this is better than requiring the
controller to support a "limit" parameter.

Use **reload** to refresh an object's data from the remote service.  You can
also get at a hash of an object's **attributes** directly if you care to.

```javascript
>>> User.find('all')
GET http://localhost:3000/users.xml
[Object _name=User _singular=user _plural=users,
  Object _name=User _singular=user _plural=users]

>>> eric = User.find('first')
GET http://localhost:3000/users.xml
Object _name=User _singular=user _plural=users

>>> eric.email
"emill@thoughtbot.com"

>>> eric.attributes()
Object active=true email=emill@thoughtbot.com id=1
>>> eric.attributes().email
"emill@thoughtbot.com"
>>> eric.email = "beverly@cleary.com"
"beverly@cleary.com"

>>> eric.reload()
GET http://localhost:3000/users/1.xml
Object _name=User _singular=user _plural=users

>>> eric.email
"emill@thoughtbot.com"
```

Ryan Schuft contributed a port of Rails' Inflector, for JavaScript.  It's
superior to the existing Inflector code libraries I've seen on the Internet, and
is a welcome edition.  He released inflector-js over the weekend, you can pick
it up there.  Jester is currently only using pluralize, but there are many great
features to it.  Thanks so much to Ryan for contributing to Jester, and for a
great string library to the JavaScript community.

[inflection-js Home](http://code.google.com/p/inflection-js/)

```javascript
>>> Base.model("Person")
>>> Person.find('all')
GET http://localhost:3000/people.xml
```

The JsUnit tests were put through a lot of work, and are now more complete and
more readable.  Interestingly, without intending to, I ended up creating
something very close to the [HttpMock test framework] that the ActiveResource
team did for ActiveResource.  My mock Internet looks like this:

[httpmock test framework]: https://thoughtbot.com/blog/activeresource-and-testing

```javascript
Internet = {}
Internet[User._singular_url(1)] = {'user': ericDetails};
Internet[Post._singular_url(1)] = {'post': postDetails};
Internet[User._plural_url()] = allUsersDetails;

// used to make sure callbacks get called
changed = false;
change = function() {changed = true;}

Base.tree.parseHTTP = function (url, options, callback) {
  call = function(doc) {change(); return callback(doc);}
  if (callback)
    return call(Internet[url]);
  else
    return Internet[url];
}
```

There's still several things I have in mind for Jester.  These are my next
targets, in order of importance:

* Scoped <abbr title="Uniform Resource Locator">URL</abbr> prefixes (e.g.
  /users/1/posts/1.xml).
* In addition to allowing a simple callback, allow a full options hash to also
  trigger asynchronous mode.  This hash would be passed directly into
  Prototype's Ajax.Request constructor.  This would allow greater control over
  callbacks, including onSuccess, onFailure, etc.
* Pack everything into only one file, jester.js, including only what I need from
  Prototype and ObjTree.  This will mean a smaller load time, and only one
  script include line in your view HTML.
* Automatic date parsing.  Dates are still returned as a string, as JavaScript's
  native Date.parse does not understand Rails' timestamp encoding.

As always, your suggestions and general feedback are very much appreciated.
