Web Service Contacts¶
Overview¶
Acrobits apps may use an external web service to load user’s contacts (address book). Web Service Contact Source can be used instead of native phone address book, or both phone address book, web service contacts and also CardDAV Contact Source can be used together. In case multiple contact sources are defined, the GUI lets the user switch between different sources.
Web Service contacts are obtained in two steps:
The app calls the web service and receives response. This response is expected to be in JSON format and should contain an array of contact objects. If you are already working with an existing contacts web service that returns an XML response, you may still use that depending on the response format. Please refer to Transformation and wsContactsXPath to learn more about utilising an existing XML contacts web service.
Transform the returned response into an internal json contact representation used by the app
The apps will call the web service periodically at a configurable interval (the default is 180 seconds).
Contacts Source Web Service¶
Parameter templates for Contacts Source Web Service can use any variables from Global parameters and Account parameters scopes.
The web service is configured on global level, either by Cloud Softphone portal, or by setting the appropriate prefKeys
directly for apps which use Acrobits SDK. The properties follow the general Acrobits Web Service Definition model, with
prefix wsContacts
:
wsContactsUrl
¶
Contains the URL, including URL scheme, of the web service, possibly also with query string.
Example:
<wsContactsUrl>https://example.com/contacts/?u=%account[username]%&p=%account[password]%</wsContactsUrl>
wsContactsMethod
¶
The HTTP method to use. Typically
GET
orPOST
. The default isGET
.
wsContactsPostData
¶
If filled in, the app will use POST request to call the web service.
Example ( for application/x-www-form-urlencoded):
u=%account[username]%&p=%account[password]%Example ( for application/json ):
{ "username" : "%account[username]%", "password" : "%account[password]%" }
wsContactsContentType
¶
Specifies the value of Content-Type header to be sent in POST request. If not specified, the app will default to
application/x-www-form-urlencoded
wsContactsAuthUsername
, wsContactsAuthPassword
¶
In case your server uses HTTP authentication, you can provide the username and password here. The apps support
Basic
andDigest
authentication, but note thatBasic
authentication will only work when using https url scheme. The app will not send passwords over plaintext connection.Example:
<wsContactsAuthUsername>%account[username]%</wsContactsAuthUsername> <wsContactsAuthPassword>%account[password]%</wsContactsAuthPassword>
wsContactsRefresh
¶
The period in seconds which determines how often will the app call the web service. The default is 180 seconds. The web service will only be called when the app is running in foreground.
wsContactsXPath
¶
In case the web service response returns XML which contains other information than just the list of contacts, this parameter tells the app where to look for contact data. See the examples for more information.
wsContactsKeywordMapping
¶
Defines the transformation between the format returned by the web service and Contacts JSON.
Response¶
The response will be considered successful if the HTTP response code is 2xx. All other responses are silently ignored.
In case the successful response contains
Last-Modified
header, the app will remember it and send its value in the next request inIf-Modified-Since
header. The server is expected to return304 Not Modified
if the contacts have not changed since the last request.
Important
It is highly recommended to include the Last-Modified
header in the response and return 304 Not Modified
response in case the contacts have not changed. The contacts can be quite big and fully reloading them periodically
(the default period is only 3 minutes!) can consume very significant bandwidth.
Examples¶
Setup¶
wsContactsUrl = https://example.com/contacts
wsContactsMethod = POST
wsContactsContentType = application/json
wsContactsPostData = {"username" : "%account[username]%","password" : "%account[password]%"}
wsContactsXPath = content/contacts
wsContactsKeywordMapping= firstName=fname,lastName=lname,organization=company,uniqueId=contactId,organizationalUnit=departmentName,lastModified=checksum,extension=contactEntries:tel
request¶
POST /example/contacts HTTP/1.1 Host: example.com Connection: close Cache-Control: max-age=0 User-Agent: CloudSoftphone/1.5.6 Content-Type: application/json If-Modified-Since: Wed, 21 Oct 2017 06:28:00 GMT {"username" : "johndow","password" : "12345"}
response¶
HTTP/1.1 200 OK Date: Sun, 15 Mar 2015 00:46:17 GMT Server: Apache/2.4.7 (Ubuntu) Content-Length: 3141 Content-Type: application/xml Last-Modified: Wed, 21 Oct 2017 07:28:00 GMT <root> <status>0</status> <message>OK</message> <content> <contacts> <contact> <avatar>https://example.com/avatar.png</avatar> <largeAvatar>https://example.com/largeAvatar.png</largeAvatar> <firstName>Jason</firstName> <lastName>Bourne</lastName> <extension>224</extension> <id>1</id> <uniqueId>d111a2e3-b806-40ce-955b-52c31996a4c7</uniqueId> <organization/> <organizationalUnit/> <creationDate>2018-01-01 16:10:45</creationDate> <lastModified>2018-01-01 17:20:13</lastModified> </contact> <contact> <firstName>James</firstName> <lastName>Bond</lastName> <extension>226</extension> <id>3</id> <uniqueId>156eea0b-872f-4e44-844b-ee19c9b3fa46</uniqueId> <organization/> <organizationalUnit/> <creationDate>2018-01-01 16:10:45</creationDate> <lastModified>2018-03-05 17:22:10</lastModified> </contact> <contact> <firstName>Johny</firstName> <lastName>English</lastName> <extension>227</extension> <id>4</id> <uniqueId>aa297ca8-5c87-4aa7-825a-5d789cea0b8c</uniqueId> <organization/> <organizationalUnit/> <creationDate>2018-01-01 16:10:45</creationDate> <lastModified>2018-01-01 17:20:39</lastModified> </contact> </contacts> </content> </root>
Discussion¶
The client has some previous response stored with Last-Modified date of Wed, 21 Oct 2017 06:28:00 GMT
. It sends this
value in If-Modified-Since
header of the request.
The server has a newer version of the contacts, by 1 hour. It sends 200 OK response with the new value in
Last-Modified
header and XML in the response body. The array of contacts is burried inside the response; the app
will use the wsContactsXPath
to get to the node with contact elements. The app will then enumerate child nodes of
this node and apply the transform described in the next section.
Example JSON response¶
In case the web service returns Content-Type: application/json
, the response should look like below. In case there is
wsContactsKeywordMapping
defined, it will be used.
{ "contacts": [{ "avatar" : "https://example.com/avatar.png", "largeAvatar" : "https://example.com/largeAvatar.png", "birthday": "1998-06-14", "checksum": "DFC1490F899CB9FD", "city": "Tiburon", "contactEntries": [{ "entryId": "tel:0", "label": "home", "type": "tel", "uri": "555-610-6679" }, { "entryId": "tel:1", "label": "work", "type": "tel", "uri": "+420 276 285 602" } ], "contactId": "E94CD15C-7964-4A9B-8AC4-10D7CFB791FD", "country": "USA", "countryCode": "us", "displayName": "David Taylor", "fname": "David", "lname": "Taylor", "notes": "Plays on Cole's Little League Baseball Team", "state": "CA", "street": "1747 Steuart Street", "zip": "949203" }, { "avatar" : "https://example.com/avatar2.png", "largeAvatar" : "https://example.com/largeAvatar2.png", "birthday": "1977-07-20", "checksum": "AAC1490F888CB9C9", "city": "Prague", "contactEntries": [{ "entryId": "tel:0", "label": "home", "type": "tel", "uri": "555-610-8888" }, { "entryId": "tel:1", "label": "work", "type": "tel", "uri": "+40 774 935 236" } ], "contactId": "AAAAD15C-7964-4A9B-8AC4-10D7CFB7983C", "country": "Czech Republic", "countryCode": "cz", "displayName": "Josef Novotny", "fname": "Josef", "lname": "Novotny", "notes": "Exists only for the purpose of testing contacts", "street": "14 Dlouha", "zip": "11150" } ] }
Transformation¶
The native format of contacts is described in Contacts JSON. In case the web service can return this format, there is nothing else to do. In case it returns XML like above, we need to define a transformation which will map the xml nodes to Contacts JSON keys.
The transform for the XML above would look like this:
firstName=fname,lastName=lname,organization=company,uniqueId=contactId,organizationalUnit=departmentName,lastModified=checksum,extension=contactEntries:tel
The transformation is a string with comma-separated entries in the form xmlNodeName=jsonKey
. In this example, we
use the correct key names for first and last name, company, department and contact identifier. The web service result
provides lastModified
value, which we can use as our internal checksum
(the value will change whenever the contact
data are modified).
This particular XML response uses only one phone number per contact, there is no array of contact entries like in our
internal representation. To deal with situations like this, there is a special syntax used in the last entry.
It tells the app to create a new element in contactEntries JSON array, set the type key to tel
and uri
key to
the value found in extension
xml node. It’s also possible to specify a label of the particular entry in contactEntries
. For example the following mapping:
extension=contactEntries_ext:tel,workNumber=contactEntries_work:tel,homeNumber=contactEntries_home:tel
will create tree phone numbers with labels ext
, work
and home
with values from XML nodes extension
, workNumber
and homeNumber
respectively.