API patterns and requirements

I've been thinking about the general interface patterns that we are using in
the some of the APIs, particularly with a focus on Contacts and System-Info.

On the one hand there is a requirement that API calls be asynchronous. On
the other hand, in order to ensure a reasonable user experience (i.e. don't
bombard the user with more than one permission request at a time) I think we
should include a requirement for serial access to each API (or collectively,
all APIs) - that no more than one API call should be executable
concurrently. I'd like to explore if this is a reasonable assumption for
e.g. Contacts and whether any changes to the pattern used may be required
for this.

The following pattern, as used in the IndexedDB specification [1], would be
applied to System-Info and Contacts APIs:

*SystemInfo API example:*

navigator.system.request.onsuccess = function() {
    var batteries = navigator.system.request.result;
    for(i in batteries) alert(batteries[i].level);
};
navigator.system.get('Power');


*Contacts API example:*

navigator.contacts.request.onsuccess = function() {
    var contacts = navigator.contacts.request.result;
    // do something with contacts
    for(i in contacts) alert(contacts[i].displayName);
}
navigator.contacts.request.onerror = function{
    var error = navigator.contacts.request.error;
    alert("[" + error.code + "]" + error.message);
}
navigator.contacts.find(['displayName', 'addresses'], {multiple: true,
limit: 3});


This pattern provides two additional benefits over the current APIs:

1. only one async method (e.g. in the Contacts API this includes find(),
save() and remove()) can be requested at any one time (i.e. serial access
only).
2. the 'result' and 'error' objects become a permanent well-known fixture on
the DOM (@ navigator.contacts.request for Contacts and
navigator.system.request for SysInfo). A common DOM node is useful if/when
integrating such APIs with HTML <input...> elements (very much in a similar
vein to the File API [2]).

In an ideal world a Contact input element would be implemented as <input
type="contact" ... /> which, on click, would bring up a 'contacts picker'
[2]. When contacts are selected by the user and this element goes in to an
equivalent of the 'File Upload' state, as defined in [3], the *.onsuccess
(or *.onerror) callbacks above would be invoked according to whatever the
current web app has specified. In any current user agent this could be
implemented as follows:

<input type="button" id="getcontacts" />
<script type="text/javascript">
    function getContacts() {
          navigator.contacts.find(['displayName', 'addresses'], {multiple:
true, limit: 3});
    }

    navigator.contacts.request.onsuccess = function() {
        var contacts = navigator.contacts.request.result;
        // do something with contacts
        for(i in contacts) alert(contacts[i].displayName);
    }
    navigator.contacts.request.onerror = function{
        var error = navigator.contacts.request.error;
        alert("[" + error.code + "]" + error.message);
    }

    // Bind button
    var el = document.getElementById("getcontacts");
    el.addEventListener("click", getContacts, false);
</script>

Final thought: we may want to bind access to navigator.contacts.* and
navigator.system.* methods to click events (specifically, bind such methods
to HTML anchor and button element click events only).

Just thought I would throw this out there as I thought it might be worth
exploring further particularly in the context of some of the feedback from
the WebApps WG. Any thoughts or developments on this proposal would be
appreciated.

regards, Richard


[1] http://www.w3.org/TR/IndexedDB/
[2] http://dev.w3.org/html5/spec/Overview.html#file-upload-state
[3] http://dev.w3.org/2009/dap/contacts/contacts_picker.png

Received on Thursday, 17 June 2010 14:24:36 UTC