Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

WebContacts API proposal

66 views
Skip to first unread message

Philipp von Weitershausen

unread,
Nov 17, 2011, 5:36:44 PM11/17/11
to dev-w...@lists.mozilla.org
Hi there,

following up to my WebContacts API musings post [1] from last week, I
wanted to see if we can get the WebContacts API to a point where the
two main target implementations (Android and native Gecko) have
something to work with.

I spent the week prototyping an IndexedDB-based storage, a simplistic
addressbook app, and some importers (see [2] for the code and [3] for
a demo; needs Firefox nightlies), so as to try and see things from
both the implementer's as well as the app author's perspective. In
doing so I've tried to address some of the IMHO shortcomings of the
existing draft specs wrt searching/filtering (points (b) and (c) in my
original email).

To date we have the W3C [4] and the WAC [5] drafts. There's also the
PhoneGap API [6] as a living, breathing example (though for the same
reasons as outlined previously, I find it rather limiting). Mike
Hanson, who worked on the Contacts Labs add-on [7], also helpfully
pointed out the Portable Contacts (PoCo) spec [8]. It has existed for
quite a while and is even (experimentally) supported by Google [9].

PoCo defines both a data schema (that is very close to what [3,4,5]
define, probably lots of cross-pollination there) as well as querying
APIs. While it's written with HTTP APIs in mind, it can easily be
adapted for a JS-facing API -- see below. I also feel it's the only
spec so far that has a compelling solution for searching/filtering and
more than that, e.g. sorting and pagination, which I didn't even go
into in my original post. Moreover, querying by modified date is
important for anybody who would want to build a contact syncing
application on top of this API. (I imagine people will.)

It's probably not worth it to bikeshed over the data schema, though I
do feel the one defined in PoCo is slightly more concise (using
'name.formatted' instead of displayName, defining individual fields
for addresses, etc.). But, really, the other ones are close enough to
that one that it probably doesn't matter. It's just a matter of
picking one :)

As for the API, I propose the following JS adaption of the PoCo API
for the navigator.contacts object:

interface Contacts {  void find(in ContactFindCB successCb,
            in ContactErrorCB errorCb,
            in ContactFindOptions options);
  void create(in ContactSuccessCB successCb,              in
ContactErrorCB errorCb,              in Contact contact);  void
update(in ContactSuccessCB successCb,              in ContactErrorCB
errorCb,              in Contact contact);  void delete(in
ContactSuccessCB successCb,              in ContactErrorCB errorCb,
          in Contact contact);}

Unlike in the WAC proposal, all manipulation methods (create, update,
delete) take the same kind of callback as defined here:
[function]interface ContactSuccessCB {  void onsuccess(in DOMString id);}

As for the 'find()' method, the 'fields', 'filter', and 'options'
parameters that are present in various API specs are merged into a
single ContactFindOptions object whose interface is based on the PoCo
query API:
interface ContactFindOptions {  /* presentation */  DOMString[] fields;
  /* filtering */  DOMString[] filterBy;  DOMString filterOp;
DOMString filterValue;  Date updatedSince;
  /* sorting */  DOMString[] sortBy;  DOMString sortOrder;
  /* pagination */  long startIndex;  long count;}

Please refer to the PoCo spec [8] for details on those fields. My only
alteration is to make filterBy and sortBy arrays to allow
filtering/sorting by multiple fields simultaneously. Implementations
may not necessarily have to support this, but it's easy enough to
spell the API this way from the start. In fact, implementations may
not have to support all querying features from the start; likewise
they could support additional features by supporting more attributes
on the ContactFindOptions object. (I imagine queries by metrics like
"recently interacted with" could be very useful.)
If people think this API is a good way forward, I'll be converting
this into a full-fledged IDL with documentation on what the behaviour
for fields and callbacks are.

Best
Philipp


[1] https://groups.google.com/group/mozilla.dev.webapi/browse_thread/thread/4ee893ec78d50bab
[2] https://github.com/philikon/webcontacts
[3] http://philikon.de/files/webcontacts/
[4] http://w3c-test.org/dap/contacts/
[5] http://specs.wacapps.net/2.0/jun2011/deviceapis/contact.html
[6] http://docs.phonegap.com/en/1.0.0/phonegap_contacts_contacts.md.html
[7] https://mozillalabs.com/contacts/
[8] http://portablecontacts.net/draft-spec.html
[9] https://code.google.com/apis/contacts/docs/poco/1.0/developers_guide.html

Philipp von Weitershausen

unread,
Nov 17, 2011, 5:48:30 PM11/17/11
to dev-w...@lists.mozilla.org
On Thu, Nov 17, 2011 at 2:36 PM, Philipp von Weitershausen
<phil...@googlemail.com> wrote:
> As for the API, I propose the following JS adaption of the PoCo API
> for the navigator.contacts object:

My apologies for the garbled output, I don't know what Gmail did
there. I posted a cleaned up version to the wiki discussion page:
https://wiki.mozilla.org/Talk:WebAPI/ContactsAPI

JOSE MANUEL CANTERA FONSECA

unread,
Nov 18, 2011, 3:39:34 AM11/18/11
to Philipp von Weitershausen, dev-w...@lists.mozilla.org
Hi,

I don't really like the pattern of successCB, errorCB. Why don't we adopt
a more promise-like approach like the one in indexedDB?

Var contactRequest = navigator.contats.find()
contactRequest.onsuccess = function() {
}
contactRequest.onerror = function() {
}

Thanks, best

El 17/11/11 23:36, "Philipp von Weitershausen" <phil...@googlemail.com>
escribió:
>As for the API, I propose the following JS adaption of the PoCo API
>for the navigator.contacts object:
>
>_______________________________________________
>dev-webapi mailing list
>dev-w...@lists.mozilla.org
>https://lists.mozilla.org/listinfo/dev-webapi


Este mensaje se dirige exclusivamente a su destinatario. Puede consultar nuestra política de envío y recepción de correo electrónico en el enlace situado más abajo.
This message is intended exclusively for its addressee. We only send and receive email on the basis of the terms set out at.
http://www.tid.es/ES/PAGINAS/disclaimer.aspx

Jason Miller

unread,
Nov 18, 2011, 8:08:11 AM11/18/11
to JOSE MANUEL CANTERA FONSECA, dev-w...@lists.mozilla.org, Philipp von Weitershausen
The only problem with that approach is that find() may want to return a cached result, and may do so before the programmer has registered those event handlers.

Wouldn't it be both logical and advantageous to adopt the same pattern used by XHR for these APIs? For example:

Var contactRequest = navigator.contacts.open(readonly);
contactRequest.onsuccess = function() {
};
contactRequest.onerror = function() {
};
contactRequest.send(searchQuery);


Regardless of how this gets implemented, as with any browser API this will be accessed through a simplified abstraction by most developers:

lib.findContacts(function(err, data) {
});

- Jason

Sent from my iPhone

Robin Berjon

unread,
Nov 18, 2011, 9:45:48 AM11/18/11
to Jason Miller, dev-w...@lists.mozilla.org
On Nov 18, 2011, at 14:08 , Jason Miller wrote:
> The only problem with that approach is that find() may want to return a cached result, and may do so before the programmer has registered those event handlers.
>
> Wouldn't it be both logical and advantageous to adopt the same pattern used by XHR for these APIs? For example:
>
> Var contactRequest = navigator.contacts.open(readonly);
> contactRequest.onsuccess = function() {
> };
> contactRequest.onerror = function() {
> };
> contactRequest.send(searchQuery);

That's a lot of noise for little actual value. It's unlikely that searching for contacts would ever require the extensibility afforded by this pattern. Much easier to just do:

navigator.findContacts(query, function (err, data) {
// ...
});

Where "err" contains the error if any, null otherwise — Node style. Cf http://scriptlib-cg.github.com/api-design-cookbook/.

--
Robin Berjon - http://berjon.com/ - @robinberjon

Rich Tibbett

unread,
Nov 18, 2011, 9:55:18 AM11/18/11
to Philipp von Weitershausen, dev-w...@lists.mozilla.org
Hi Phillip,

FWIW, people often overlook that the W3C also worked on a Contacts
Writer API [CONTACTS-WRITER-API] specification also. This is the
document that is implemented by, for example, PhoneGap
[PHONEGAP-CONTACTS-WRITER-IMPL], to supplement the basic W3C Contacts
API [CONTACTS-API] that rightly gets a lot more attention.

It was decided to split writeback functions out to a separate spec
because nobody could come up with any reasonable, workable UI paradigms
for writeback operations to occur within today's web browsers. We could
start presenting doorhanger notifications (aka Geoloc) whenever a
writeback operation is invoked but the risk is one of killing the
in-page experience. What UI, if any, do you anticipate when a user calls
create(), update() or delete() methods in this API?

Instead of requiring these methods we worked towards the 'download and
save' paradigm for writebacks that is common in web browsers today for
e.g. saving files to the local filesystem. When a page wants to write
back to an Address Book store it invokes a 'file'. It just happens that
the behavior of the browser when it receives a Contacts file could be
different to that of other files. For example, a browser could ask the
user if they want to save that to their UA-provided address book, save
it as a (valid vCard) file on their machine or simply open that (valid
vCard) file with their preferred Address Book software.

This was more about making it work in browsers than simply defining
methods and working out the UI implications later. They are one and the
same. Due to thse problems work around the W3C Contacts Writer API
stalled while provisions were made for writeback in the W3C Contacts API
hooking in to well-known UI paradigms in browsers.

br/ Rich Tibbett

[CONTACT-WRITER-API] http://w3c-test.org/dap/contacts/Writer.html
[CONTACTS-API] http://w3c-test.org/dap/contacts/

[PHONEGAP-CONTACTS-WRITER-IMPL]
http://docs.phonegap.com/en/1.0.0/phonegap_contacts_contacts.md.html
--
Rich Tibbett
Opera Software ASA


Rich Tibbett

unread,
Nov 18, 2011, 9:57:00 AM11/18/11
to Philipp von Weitershausen, dev-w...@lists.mozilla.org
Rich Tibbett wrote:
> Hi Phillip,
>
> FWIW, people often overlook that the W3C also worked on a Contacts
> Writer API [CONTACTS-WRITER-API] specification also. This is the
> document that is implemented by, for example, PhoneGap
> [PHONEGAP-CONTACTS-WRITER-IMPL], to supplement the basic W3C Contacts
> API [CONTACTS-API] that rightly gets a lot more attention.
>
> It was decided to split writeback functions out to a separate spec
> because nobody could come up with any reasonable, workable UI paradigms
> for writeback operations to occur within today's web browsers. We could
> start presenting doorhanger notifications (aka Geoloc) whenever a
> writeback operation is invoked but the risk is one of killing the
> in-page experience. What UI, if any, do you anticipate when a user calls
> create(), update() or delete() methods in this API?
>
> Instead of requiring these methods we worked towards the 'download and
> save' paradigm for writebacks that is common in web browsers today for
> e.g. saving files to the local filesystem. When a page wants to write
> back to an Address Book store it invokes a 'file'. It just happens that
> the behavior of the browser when it receives a Contacts file could be
> different to that of other files. For example, a browser could ask the
> user if they want to save that to their UA-provided address book, save
> it as a (valid vCard) file on their machine or simply open that (valid
> vCard) file with their preferred Address Book software.

See: http://w3c-test.org/dap/contacts/#adding-and-updating-contacts

Keith Erskine

unread,
Nov 18, 2011, 10:00:31 AM11/18/11
to mozilla.d...@googlegroups.com, dev-w...@lists.mozilla.org
Philipp - would WebAPI also handle import, export, and possible syncing with SIM card contact data?
Message has been deleted

Jason Miller

unread,
Nov 18, 2011, 10:30:58 AM11/18/11
to Robin Berjon, dev-w...@lists.mozilla.org
@Robin - Did you see the second part of my message?

I actually think a search API is one of the most likely use cases for
extensibility. By definition, search is an operation with variable
input. Regardless
of how many lines of code the API would require to implement, there are
fundamental things wrong with relying *solely* on ordered parameters to a
single function for something this complex (search *is* complex, regardless
of how simple you can make the API look). What if you want to allow search
modifiers? What about letting an application request access to the API
before using it, possibly allowing the app to request access to a subset of
the data, or a particular group of functionality (read-only, create, edit,
all)?

The whole point of using a promise is that you give developers a foundation
on which they can build their applications that won't change. If the
entire "find contacts" API were to be represented as a single function
call, they only way to do that would be through an options object -
something generally not found in browser APIs:

navigator.contacts.find(query, { access:'readonly' }, function(err, data) {
});

I love this pattern, and I use it often in my NodeJS and framework
development. However, it does not align with any of the current browser
APIs, and I think the pattern used is foreign to many client-side
JavaScript developers. The problem you can see right away when you look at
code like the above example is that the "options" object *requires*
documentation to understand. Documentation is lovely and all, but self
documenting code with documentation would certainly be a better goal when
designing for the web. Since open() would return an instance of
window.ContactQuery (naming aside), a developer can *very* easily inspect
both the instance and the globally referencable prototype to get a very
clear understanding of what functionality is available.

Inevitably, there is a tradeoff between "simplicity" and building to be
future-proof. If the browser is any lesson, everyone can probably agree
future-proof should be the better choice.

Use a solid, extensible API. Build your own "simpler" tools on top of that
if you wish. It will save everyone a lot of headache when these APIs
change, without changing their interfaces.

Note: Here's your glue:
lib.contacts.find = function(query, opt, cb) {
var r;
opt = opt || {};
try {
r = navigator.contacts.open(opt.access);
} catch(err) {
return cb(err);
}
r.onsuccess = function(data) {
cb(false, data);
};
r.onerror = function(err) {
cb(err);
};
return r.send(query);
};

- Jason

Philipp von Weitershausen

unread,
Nov 18, 2011, 3:01:39 PM11/18/11
to JOSE MANUEL CANTERA FONSECA, dev-w...@lists.mozilla.org
On Fri, Nov 18, 2011 at 12:39 AM, JOSE MANUEL CANTERA FONSECA
<jm...@tid.es> wrote:
> Hi,
>
> I don't really like the pattern of successCB, errorCB. Why don't we adopt
> a more promise-like approach like the one in indexedDB?
>
> Var contactRequest = navigator.contats.find()
> contactRequest.onsuccess = function() {
> }
> contactRequest.onerror = function() {
> }

This is a good question. I would certainly welcome being consistent
with existing web APIs (and the ones we're going to build), although
personally I find this to be a rather noisy way of spelling things.
Like Jason points out, people would almost certainly build a helper
that takes one callback and performs the API mechanics -- I know I
would ;)

Also, one question we might want to figure out for this scheme is
whether the 'error' event would bubble up to anything, like it does
with IndexedDB. I have found that the bubbling is very useful for
generic error handling and such.

Philipp von Weitershausen

unread,
Nov 18, 2011, 3:06:23 PM11/18/11
to Jason Miller, JOSE MANUEL CANTERA FONSECA, dev-w...@lists.mozilla.org
On Fri, Nov 18, 2011 at 5:08 AM, Jason Miller <ja...@developit.ca> wrote:
> The only problem with that approach is that find() may want to return a cached result, and may do so before the programmer has registered those event handlers.

Well, it doesn't have be a problem. You would just have to make sure
that the events are never dispatched synchronously. If you wait at
least one event loop tick, the caller will have had enough time to
attach event handlers.

> Wouldn't it be both logical and advantageous to adopt the same pattern used by XHR for these APIs? For example:
>
> Var contactRequest = navigator.contacts.open(readonly);
> contactRequest.onsuccess = function() {
> };
> contactRequest.onerror = function() {
> };
> contactRequest.send(searchQuery);

Hmm, interesting. The explicit "open" and "send" actions nicely mirror
how other I/O operations work, but I'm a bit worried about the
signal-to-noise ratio...

Philipp von Weitershausen

unread,
Nov 18, 2011, 3:29:35 PM11/18/11
to Rich Tibbett, dev-w...@lists.mozilla.org
Thanks for the historical background, Rich! Detailed comments inline below:

On Fri, Nov 18, 2011 at 6:55 AM, Rich Tibbett <ri...@opera.com> wrote:
> Hi Phillip,
>
> FWIW, people often overlook that the W3C also worked on a Contacts Writer
> API [CONTACTS-WRITER-API] specification also.

Thanks, I somehow missed then when I was doing my research.

> It was decided to split writeback functions out to a separate spec because
> nobody could come up with any reasonable, workable UI paradigms for
> writeback operations to occur within today's web browsers. We could start
> presenting doorhanger notifications (aka Geoloc) whenever a writeback
> operation is invoked but the risk is one of killing the in-page experience.
> What UI, if any, do you anticipate when a user calls create(), update() or
> delete() methods in this API?

Wearing my open web app (e.g. B2G) developer hat, I would not
anticipate any UI other than the one I write myself, e.g. for an
Address Book application. This is assuming that my app already has
permissions to read and write contacts. The permissions would be
sticky, of course, so once granted (in the open web app case I would
assume at installation time, on the web perhaps via doorhanger a la
geoloc), they would not have to be requested.

> Instead of requiring these methods we worked towards the 'download and save'
> paradigm for writebacks that is common in web browsers today for e.g. saving
> files to the local filesystem. When a page wants to write back to an Address
> Book store it invokes a 'file'. It just happens that the behavior of the
> browser when it receives a Contacts file could be different to that of other
> files. For example, a browser could ask the user if they want to save that
> to their UA-provided address book, save it as a (valid vCard) file on their
> machine or simply open that (valid vCard) file with their preferred Address
> Book software.

Yeah, that's how I understood those sections in [CONTACTS-API] and I
get where you're coming from. I'm just not sure this is very helpful
for people who want to build contact management and synchronization
apps. These are use cases we are almost certainly going to have in B2G
and they require sufficiently capable APIs for querying and
manipulating contacts, without user interaction.

> This was more about making it work in browsers than simply defining
> methods and working out the UI implications later. They are one and the
> same.

Maybe (probably!) I'm being very naive, but I don't see the UI as a
large obstacle. Would you mind elaborating or pointing me to some of
the discussion revolving around that point?

Jason Miller

unread,
Nov 18, 2011, 3:32:47 PM11/18/11
to Philipp von Weitershausen, JOSE MANUEL CANTERA FONSECA, dev-w...@lists.mozilla.org
One dispute I have with the (err, data) callback signature used in NodeJS
is that it gives preferential treatment to error callbacks rather than
success callbacks. If the argument order were to be reversed, the error
callback can (understandably) still be passed a data parameter, which can
be discarded. Merging those two function signatures gives you the
flexibility of the NodeJS unified callback style, while retaining the
ability to care about both. Here's an API use case I'd love to see:

var c = navigator.contacts.open(readonly);
c.onsuccess = c.onerror = function(data, err) {
// one function handles both cases
};
c.send(query);

If the functions were chainable, another alternative would be to allow the
programmer to specify callbacks in open() or send(), while still allowing
them to be registered as standard event handlers:
var c = navigator.contacts.open(readonly).send(query, callback);
c.onerror = function() {
// another callback
};

However, you can see that the open() call failing would break this code
horribly.

Taking the suggestion to defer any would-be synchronous events, perhaps the
promise approach could be used. find() would have to defer more than just
the event firing, however, to allow modifications on the returned object
*before* actually going and executing the contacts query. That situation
is sub-optimal, but it is a relatively concise API that retains some of the
good parts of the XHR interface.

- Jason

Philipp von Weitershausen

unread,
Nov 18, 2011, 3:36:16 PM11/18/11
to mozilla.d...@googlegroups.com, dev-w...@lists.mozilla.org
On Fri, Nov 18, 2011 at 7:00 AM, Keith Erskine <keith....@gmail.com> wrote:
> Philipp - would WebAPI also handle import, export, and possible syncing with SIM card contact data?

Good question.

On Android we're planning on making navigator.contacts reflect the
data in the native contacts content provider. That might already
reflect SIM card data? I'm not sure.

For B2G, we could synchronize with the SIM card. Or we could leave
this up to an app to do it, assuming we sufficiently expose SIM card
access as web APIs. I'm certainly fond of the idea of being able to
implement address book synchronizers as web apps.

Philipp von Weitershausen

unread,
Nov 18, 2011, 3:46:45 PM11/18/11
to JOSE MANUEL CANTERA FONSECA, dev-w...@lists.mozilla.org
On Fri, Nov 18, 2011 at 12:01 PM, Philipp von Weitershausen
<phil...@googlemail.com> wrote:
> On Fri, Nov 18, 2011 at 12:39 AM, JOSE MANUEL CANTERA FONSECA
> <jm...@tid.es> wrote:
>> Hi,
>>
>> I don't really like the pattern of successCB, errorCB. Why don't we adopt
>> a more promise-like approach like the one in indexedDB?
>>
>> Var contactRequest = navigator.contats.find()
>> contactRequest.onsuccess = function() {
>> }
>> contactRequest.onerror = function() {
>> }
>
> This is a good question. I would certainly welcome being consistent
> with existing web APIs (and the ones we're going to build), although
> personally I find this to be a rather noisy way of spelling things.

(Of course, "consistency" is to be taken cum grano salis here since
the success/error callback pattern already has a precedent in the
geoloc API.)

Philipp von Weitershausen

unread,
Nov 18, 2011, 6:36:21 PM11/18/11
to dev-w...@lists.mozilla.org
On Thu, Nov 17, 2011 at 2:48 PM, Philipp von Weitershausen
<phil...@googlemail.com> wrote:
> On Thu, Nov 17, 2011 at 2:36 PM, Philipp von Weitershausen
> <phil...@googlemail.com> wrote:
>> As for the API, I propose the following JS adaption of the PoCo API
>> for the navigator.contacts object:
>
> My apologies for the garbled output, I don't know what Gmail did
> there. I posted a cleaned up version to the wiki discussion page:
> https://wiki.mozilla.org/Talk:WebAPI/ContactsAPI

I cleaned up the WebIDL definitions, added some comments, and adopted
the ContactsWriter API for record manipulation as pointed out by Rich.
See https://github.com/philikon/webcontacts/tree/master/idl. Feedback
is, as always, very welcome (via email, inline comments on GitHub, or
whatever.)

I'll be updating my IDB-based implementation and demo apps next.

Rich Tibbett

unread,
Nov 21, 2011, 2:26:45 AM11/21/11
to Philipp von Weitershausen, dev-w...@lists.mozilla.org
Philipp von Weitershausen wrote:
> On Fri, Nov 18, 2011 at 6:55 AM, Rich Tibbett<ri...@opera.com> wrote:
>>
>> FWIW, people often overlook that the W3C also worked on a Contacts Writer
>> API [CONTACTS-WRITER-API] specification also.
>
> Thanks, I somehow missed then when I was doing my research.
>
>> It was decided to split writeback functions out to a separate spec because
>> nobody could come up with any reasonable, workable UI paradigms for
>> writeback operations to occur within today's web browsers. We could start
>> presenting doorhanger notifications (aka Geoloc) whenever a writeback
>> operation is invoked but the risk is one of killing the in-page experience.
>> What UI, if any, do you anticipate when a user calls create(), update() or
>> delete() methods in this API?
>
> Wearing my open web app (e.g. B2G) developer hat, I would not
> anticipate any UI other than the one I write myself, e.g. for an
> Address Book application. This is assuming that my app already has
> permissions to read and write contacts. The permissions would be
> sticky, of course, so once granted (in the open web app case I would
> assume at installation time, on the web perhaps via doorhanger a la
> geoloc), they would not have to be requested.

So herein lies the main problem. If we can provide up-front permissions
on 'install', whatever that comes to mean, then we can present such
writeback API methods without having to do any authorization-blocking
towards the user (or worse, any stacking of pending authorizations
towards the user).

You have to like the efficiency of the 'download to save' UI paradigm
for write-back operations, not least because downloading and saving
files is something that all web users are familiar with today. By
default the UA could handle such operations (as explained below). Then
there is no reason that Contact-card handling could not be delegated out
to a web app so when such a file is invoked it gets send to that
provider (e.g. mail.google.com could register a HTML5 'content handler'
for Contact files). If I had mail.google.com configured as a Contacts
information provider, those changes would then get written back to the
main UA Contacts data store on next mail.google.com sync anyway. In
summary, the paradigm works fairly well.

Regarding delete operations we really struggled to see this as ever
needing to be a function of a web application. Instead we want to
provide some browser-native management UI (i.e. I can delete Contacts
via an browser-internal Contacts Manager view @ e.g. 'about:contacts')
without providing a way for a web application to delete Contact records
programmatically).

>
>> Instead of requiring these methods we worked towards the 'download and save'
>> paradigm for writebacks that is common in web browsers today for e.g. saving
>> files to the local filesystem. When a page wants to write back to an Address
>> Book store it invokes a 'file'. It just happens that the behavior of the
>> browser when it receives a Contacts file could be different to that of other
>> files. For example, a browser could ask the user if they want to save that
>> to their UA-provided address book, save it as a (valid vCard) file on their
>> machine or simply open that (valid vCard) file with their preferred Address
>> Book software.
>
> Yeah, that's how I understood those sections in [CONTACTS-API] and I
> get where you're coming from. I'm just not sure this is very helpful
> for people who want to build contact management and synchronization
> apps. These are use cases we are almost certainly going to have in B2G
> and they require sufficiently capable APIs for querying and
> manipulating contacts, without user interaction.
>
>> This was more about making it work in browsers than simply defining
>> methods and working out the UI implications later. They are one and the
>> same.
>
> Maybe (probably!) I'm being very naive, but I don't see the UI as a
> large obstacle. Would you mind elaborating or pointing me to some of
> the discussion revolving around that point?

I guess the following is a good summary of the issues (though by no
means is it an exhaustive summary):

http://lists.w3.org/Archives/Public/public-device-apis/2010Jul/0112.html

roc also made a good summary of the 'permissions for web apps' problem
which should also be of interest:

http://robert.ocallahan.org/2011/06/permissions-for-web-applications_30.html

In the context of that post the W3C Contacts Read/Write work focused on
the 'Implicit Permission Grants' model described therein.

HTH, Rich

Mounir Lamouri

unread,
Nov 22, 2011, 6:25:36 AM11/22/11
to dev-w...@lists.mozilla.org
Jonas told me returing an object and sending events to the object was
generally preferred by web authors and that's why IndexedDB does that
(IIRC). WebSMS is doing that such as WebTelefony. I believe Contacts API
should try to be consistent here.

By the way, wouldn't that be better to have the draft in wiki.mozilla.org?

--
Mounir

Vivien

unread,
Nov 23, 2011, 12:00:36 PM11/23/11
to dev-w...@lists.mozilla.org
On 17/11/2011 23:48, Philipp von Weitershausen wrote:
> On Thu, Nov 17, 2011 at 2:36 PM, Philipp von Weitershausen
> <phil...@googlemail.com> wrote:
>> As for the API, I propose the following JS adaption of the PoCo API
>> for the navigator.contacts object:
> My apologies for the garbled output, I don't know what Gmail did
> there. I posted a cleaned up version to the wiki discussion page:
> https://wiki.mozilla.org/Talk:WebAPI/ContactsAPI
> _______________________________________________
>

Hey,
I have started to write an application using the proposed API for B2G,
and more specifically Gaia, the B2G Front-End.
The API has slightly changed since I have used it but here is my first
impressions.

----
/**
* This is the read-only portion API of the navigator.contacts object.
*/
[NoInterfaceObject]
interface Contacts {
void find(ContactFindCB successCb,
ContactErrorCB errorCb,
ContactFindOptions options);
};
----

Using the find API I've found myself giving fake |function() {}| just to
make the API happy. I was not really interested in any errors, and even
if it's really bad in terms of QA, it's often the way it works on the web.

I think this API focused too much on the callback mechanism while what I
have really in mind while using it is the result at the end.
And this result will be filtered, ordered, etc by the ContactFindOptions
parameter. This is probably the parameter that should be the first.

In my opinion it should also be the only one required since this way I
can decided to write an application that do not care about errors, or
even an application that only cares about error to check the validity of
the database.

People can say that's bad to not care about error but I've not seen that
much |onerror| handler used for XHR on the web.

The simplest API to use for me is:
----
var request = window.navigator.contacts.find(options);
request.onsuccess = function() {};
request.error = function() {};
----

Also, actually the success callback returns an array of Contacts and
this can potentialy be a memory monster and slow.
People can argue that this can be avoided by specifying the |fields| in
the ContactFindOptions parameter. That's true but I have comments on
that (see a few lines below), and to resume this expect the web
developer to think about it.
But there is an other approach that does not rely on that fact and has
been taken by the WebSMS API.

request.onsuccess = function() {
var result = request.result;
};

|result| is an Iterator that returns a full SMS object in a lightweight
manner without expecting me to care about memory issues.
In my opinion, This is far more elegant and efficient.

----
/**
* (Taken verbatim from W3C Editor's Draft 10 November 2011)
*/
[NoInterfaceObject]
interface ContactError {
const unsigned short UNKNOWN_ERROR = 0;
const unsigned short INVALID_ARGUMENT_ERROR = 1;
const unsigned short TIMEOUT_ERROR = 2;
const unsigned short PENDING_OPERATION_ERROR = 3;
const unsigned short IO_ERROR = 4;
const unsigned short NOT_SUPPORTED_ERROR = 5;
const unsigned short PERMISSION_DENIED_ERROR = 20;
readonly attribute unsigned short code;
};
----

The |onerror| case follow the same principle of having the values set on
the request object instead of passing a parameter to the error callback.

request.onerror = function() {
console.log(request.errorCode + ':' + request.errorMessage);
};

This get rid of the ContactError interface.



----
/**
* Object specifying search options.
*
* Based on the Portable Contacts query API
* (http://portablecontacts.net/draft-spec.html). The only difference is
* that 'filterBy' and 'sortBy' are arrays of strings instead of a single
* string value, to allow filtering and sorting by multiple values
* simultaneously.
*/
[NoInterfaceObject]
interface ContactFindOptions {
/* presentation */

/**
* Search qualifier.
*
* The W3C draft requires this to have non-zero length, which means one
* must always explicitly state the fields which can be pretty tedious.
* Although analogous to SQL's SELECT, one could define "*"
matching all
* possible fields.
*/
attribute DOMString[]? fields;
----

As said before this is something I think is unuseful if we use an Iterator.
Also in my opinion, the backend sue here. As a developer using this API
I don't really want to see the backend I want to to received filtered
Contacts, not some part of the Contacts which will obliged me to use the
|find| API later again if I want to know more.

I tend to think that people are lazy and will often use '*' here.



----
/* filtering */

/**
* List of one or more field names that 'filterOp' and
'filterValue' are
* applied to. If this is provided, at least 'filterOp' must be
provided
* too. A record matches when the filter matches at least one of the
* specified fields' values.
*/
attribute DOMString[]? filterBy;

/**
* Filter operation to perform. Valid operations are
* - 'present': the field value must be non-empty.
* - 'equals': the field value must be identical to the 'filterValue'.
* - 'contains': 'filterValue' must be a substring of the field value.
* - 'startswith': 'filterValue' must be a substring of the field
value,
* starting at the beginning.
* - 'iequals', 'icontains', 'istartswith' work like their respective
* equivalents, but they ignore case.
*/
attribute DOMString? filterOp;

/**
* Value to filter by, using the comparison method specified by
'filterOp'.
*/
attribute DOMString? filterValue;
----

I have not used the filtering API but I think this is part of a much
bigger discussion to have something that looks unified between all APIs
and worth a thread just by itself.



----
/**
* Only return records that have been added or modified since this
time.
*/
attribute Date? updatedSince;
----

What is the use case here?



----
/* sorting */

/**
* List of one or more field names to sort records by. Records will
first
* be sorted by the first field, then the second, and so forth. Sorting
* by plural fields will sort according to the entry marked primary.
*/
attribute DOMString[]? sortBy;

/**
* Order in which the sorting is to be done. Valid values are
* - 'ascending' (default)
* - 'descending'
*/
attribute DOMString? sortOrder;
----

I have not really used the sorting (it was not usable in the API I have
played with) but again I think this should be part of a bigger
discussion to have something unified between all the APIs.



----
/* pagination */

/**
* Specify the offset of the first result to be returned with respect
* to the total list of records matching the query. This must be non-
* negative and defaults to 0.
*/
attribute long? startIndex;

/**
* Specified the number of records to be returned, if non-zero.
Defaults
* to 0.
*/
attribute long? count;
----

I'm not sure this is needed if the result is an iterator since it will
then depends on how many Contacts you want to read from the Iterator.

----
};
----


I don't have strong opinion about the ContactsWriter since I've not used
it a lot (and the API it's not implemented ;)).
But I would like to see a method to import a lot of contacts instead of
having to do a loop that call the create method.


----
/**
* (Taken verbatim from ContactsWriter draft)
*/
[NoInterfaceObject]
interface ContactsWriter : Contacts {
Contact create(ContactProperties properties);
};

/**
* (Taken verbatim from ContactsWriter draft)
*/
[NoInterfaceObject]
interface ContactWriter : ContactProperties {
void save(ContactSuccessCB successCb,
ContactErrorCB errorCb);
void remove(ContactSuccessCB successCb,
ContactErrorCB errorCb);
Contact clone();
};

/**
* A Contact object combines the fields from ContactProperties and the
methods
* from ContactWriter. On top of that it contains read-only attributes
set by
* the database.
*/
[NoInterfaceObject]
interface Contact : ContactWriter {
readonly attribute DOMString id;

readonly attribute Date? published;
readonly attribute Date? updated;
};

/**
* (Taken verbatim from ContactsWriter draft)
*/
[Callback=FunctionOnly, NoInterfaceObject]
interface ContactSuccessCB {
void onsuccess (Contact contact);
};

/**
* (Taken verbatim from W3C Editor's Draft 10 November 2011)
*/
[Callback=FunctionOnly, NoInterfaceObject]
interface ContactErrorCB {
void onerror (ContactError error);
};
----


I will have more input once I will played more with the API.

0 new messages