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.