Contacts API v2

Google Contacts API v2 Developer's Guide - Java

Important: Versions 1 and 2 of the Google Contacts API have been officially deprecated as of April 20, 2012. They will continue to work as per our deprecation policy, but we encourage you to move to version 3.

The Contacts Data API allows client applications to view and update a user's contacts. Contacts are stored in the user's Google Account; most Google services have access to the contact list.

Your client application can use the Contacts Data API to create new contacts, edit or delete existing contacts, and query for contacts that match particular criteria.

In addition to providing some background on the capabilities of the Contacts Data API, this document provides examples of how to interact with contacts using the Java client library. If you're interested in understanding more about the underlying protocol that the library uses, see the Protocol section of this developer's guide.

Contents

Audience

This document is intended for programmers who want to write Java client applications that can interact with Google's contact lists.

This document assumes that you understand the general ideas behind the Google Data APIs protocol.

For reference information about the classes and methods provided by the client library, see the Java client library API reference. For general Contacts Data API reference information, see the Protocol reference guide.

Getting started

For help setting up the client library, see the Getting Started Guide.

The Java client library requires Java 1.5. After downloading the client library, you'll find the classes you need to get started in the java/lib/gdataclient-X.Y.jar file.

Creating a Google Account

You may want to sign up for a Google Account for testing purposes. Contacts are associated with Google Accounts, so if you already have a Google Account, you're all set.

Note: To view your contacts without using the Contacts Data API, you can log in to Gmail and click the Contacts link.

Running the sample code

A full working sample client, containing all the sample code shown in this document, is available in the Java client library distribution, under the directory gdata/java/sample/contacts/ContactsExample.java. Build and execution instructions are included in the same directory in the README.txt file.

The sample client performs several operations on contacts to demonstrate the use of the Contacts Data API.

To compile the examples in this document into your own code, you'll need the following import statements:

import com.google.gdata.client.*;
import com.google.gdata.client.contacts.*;
import com.google.gdata.data.*;
import com.google.gdata.data.contacts.*;
import com.google.gdata.data.extensions.*;
import com.google.gdata.util.*;
import java.io.IOException;
import java.net.URL;

Authenticating

All Contacts Data API feeds are private. Thus, your client needs to authenticate before accessing a contacts feed. It can authenticate using either of two approaches: ClientLogin username/password authentication or AuthSub proxy authentication.

For more information about authentication with Google Data APIs in general, see the authentication documentation.

AuthSub proxy authentication

AuthSub proxy authentication is used by web applications that need to authenticate their users to Google Accounts. The website operator and the client code don't have access to the username and password for the user; instead, the client obtains special AuthSub tokens that allow the client to act on a particular user's behalf. For more detailed information, see the AuthSub documentation.

When a user first visits your application, they have not yet been authenticated. In this case, you need to display some information and a link directing the user to a Google page to authenticate your request for access to their contacts. The Java client library provides a function to generate the Google page's URL from the AuthSubUtil class. The code below retrieves the URL of the AuthSubRequest page:

String next = "http://www.example.com/welcome.html";
String scope = "http://www.google.com/m8/feeds/";
boolean secure = false;
boolean session = true;
String authSubLogin = AuthSubUtil.getRequestUrl(next, scope, secure, session);

The getRequestUrl method takes the following parameters (corresponding to the query parameters used by the AuthSubRequest handler):

next
The URL of the page that Google should redirect the user to after authentication.
scope
Indicates that the application is requesting a token to access contacts feeds. The scope string to use is http://www.google.com/m8/feeds/.
secure
Indicates whether the client is requesting a secure token.
session
Indicates whether the token returned can be exchanged for a multi-use (session) token.

The above example shows a call that doesn't request a secure token (the value of secure is false). The resulting request URL might look like this:

https://www.google.com/accounts/AuthSubRequest?scope=http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds%2F&session=1&secure=0&next=http%3A%2F%2Fwww.example.com%2Fwelcome.html

The user follows the link to Google's site and authenticates to their Google Account.

After the user authenticates, the AuthSub system redirects them to the URL you specified in the next query parameter of the AuthSubRequest URL. The AuthSub system appends an authentication token to that URL, as the value of the token query parameter. For example:

http://www.example.com/welcome.html?token=yourAuthToken

This token value represents a single-use AuthSub token. In this example, since session = true was specified, this token can be exchanged for an AuthSub session token by calling the AuthSubSessionToken service with the single-use token in an Authorization header, as follows, where urlFromAuthSub is the URL that AuthSub appended the token to:

String token = AuthSubUtil.getTokenFromReply(urlFromAuthSub);
String sessionToken = AuthSubUtil.exchangeForSessionToken(token, null);

That is, you pass your one-time-use token to the exchangeForSessionToken method, along with either null (if you aren't using enhanced security) or a private key (for more security), and the AuthSub interface returns a session token. For more information about registered applications and private keys, refer to the "Signing requests" section of the AuthSub documentation.

Your application can then use the session token in subsequent interactions with the Contacts API. To tell the Java client library to automatically send the session token with each request, call your ContactsService object's setAuthSubToken method. As before, the second argument is used to provide a private key for signed requests.

ContactsService.setAuthSubToken(sessionToken, null);

After that, the client library automatically sends the token along with every request.

ClientLogin username/password authentication

Use ClientLogin authentication if your client is a standalone, single-user "installed" client (such as a desktop application). Just call the setUserCredentials method on your ContactsService object and all subsequent interactions with contacts will be authenticated:

ContactsService myService = new ContactsService("exampleCo-exampleApp-1");
myService.setUserCredentials("liz@gmail.com", "password");

For more information about ClientLogin authentication, including sample requests and responses, see the Account Authentication for Installed Applications documentation.

Creating contacts

You can use the Java client library to publish new contact entries.

First, create a ContactEntry object to represent the contact. Then you can set the name, notes and other attributes of the contact. Finally, use the ContactsService object to insert the contact. Here's an example of how to publish a new contact:

public static ContactEntry createContact(ContactsService myService,
    String name, String notes)
    throws ServiceException, IOException {
  // Create the entry to insert
  ContactEntry contact = new ContactEntry();
  contact.setTitle(new PlainTextConstruct(name));
  contact.setContent(new PlainTextConstruct(notes));

  Email primaryMail = new Email();
  primaryMail.setAddress("liz@gmail.com");
  primaryMail.setRel("http://schemas.google.com/g/2005#home");
  primaryMail.setPrimary(true);
  contact.addEmailAddress(primaryMail);

  Email secondaryMail = new Email();
  secondaryMail.setAddress("liz@example.com");
  secondaryMail.setRel("http://schemas.google.com/g/2005#work");
  secondaryMail.setPrimary(false);
  contact.addEmailAddress(secondaryMail);

  ExtendedProperty favouriteFlower = new ExtendedProperty();
  favouriteFlower.setName("favourite flower");
  favouriteFlower.setValue("daisy");
  contact.addExtendedProperty(favouriteFlower);

  ExtendedProperty sportsProperty = new ExtendedProperty();
  sportsProperty.setName("sports");
  XmlBlob sportKinds = new XmlBlob();
  sportKinds.setBlob(new String("<dance><salsa/><ballroom dancing/><dance/>"));
  spsportsPropertyorts.setXmlBlob(sportKinds);
  contact.addExtendedProperty(sportsProperty);

  // Ask the service to insert the new entry
  URL postUrl = new URL("https://www.google.com/m8/feeds/contacts/liz@gmail.com/full");
  return myService.insert(postUrl, contact);
}

The insert method takes the service's POST URL as a parameter. Then the method returns the entry as it was stored by the server. The entry returned is the same one you sent, but it also contains various elements added by the server, such as a contact ID.

If your request fails for some reason, Google may return a different status code. For information about the status codes, see the Google Data API protocol reference document.

Note: A photo cannot be added to a contact while creating the contact.

Adding a photo for a contact

When adding a photo, setting a proper ContentType is important.

Example of adding a photo in a JPEG format:

  public static void addContactPhoto(ContactEntry entry, ContactsService service, byte[] photoData)
      throws ServiceException, IOException {
    Link photoLink = entry.getContactPhotoLink();
    URL photoUrl = new URL(photoLink.getHref());

    GDataRequest request = service.createRequest(GDataRequest.RequestType.UPDATE,
        photoUrl, new ContentType("image/jpeg"));

    OutputStream requestStream = request.getRequestStream();
    requestStream.write(photoData);

    request.execute();
  }

Retrieving contacts

Retrieving all contacts

To retrieve the user's contacts, call the getFeed method with the contact feed URL:

public static void printAllContacts(ContactsService myService)
    throws ServiceException, IOException {
  // Request the feed
  URL feedUrl = new URL("https://www.google.com/m8/feeds/contacts/liz@gmail.com/full");
  ContactFeed resultFeed = myService.getFeed(feedUrl, ContactFeed.class);
  // Print the results
  System.out.println(resultFeed.getTitle().getPlainText());
  for (int i = 0; i < resultFeed.getEntries().size(); i++) {
    ContactEntry entry = resultFeed.getEntries().get(i);
    System.out.println("\t" + entry.getTitle().getPlainText());

    System.out.println("Email addresses:");
    for (Email email : entry.getEmailAddresses()) {
      System.out.print(" " + email.getAddress());
      if (email.getRel() != null) {
        System.out.print(" rel:" + email.getRel());
      }
      if (email.getLabel() != null) {
        System.out.print(" label:" + email.getLabel());
      }
      if (email.getPrimary()) {
        System.out.print(" (primary) ");
      }
      System.out.print("\n");
    }

    System.out.println("IM addresses:");
    for (Im im : entry.getImAddresses()) {
      System.out.print(" " + im.getAddress());
      if (im.getLabel() != null) {
        System.out.print(" label:" + im.getLabel());
      }
      if (im.getRel() != null) {
        System.out.print(" rel:" + im.getRel());
      }
      if (im.getProtocol() != null) {
        System.out.print(" protocol:" + im.getProtocol());
      }
      if (im.getPrimary()) {
        System.out.print(" (primary) ");
      }
      System.out.print("\n");
    }

    System.out.println("Groups:");
    for (GroupMembershipInfo group : entry.getGroupMembershipInfos()) {
      String groupHref = group.getHref();
      System.out.println("  Id: " + groupHref);
    }

    System.out.println("Extended Properties:");
    for (ExtendedProperty property : entry.getExtendedProperties()) {
      if (property.getValue() != null) {
        System.out.println("  " + property.getName() + "(value) = " +
            property.getValue());
      } else if (property.getXmlBlob() != null) {
        System.out.println("  " + property.getName() + "(xmlBlob)= " +
            property.getXmlBlob().getBlob());
      }
    }

    String photoLink = entry.getContactPhotoLink().getHref();
    System.out.println("Photo Link: " + photoLink);

    if (photoLink.getEtag() != null) {
      System.out.println("Contact Photo's ETag: " + photoLink.getEtag());
    }

    System.out.println("Contact's ETag: " + entry.getEtag());
  }
}

Note: The feed may not contain all of the user's contacts, because there's a default limit on the number of results returned. For more information, see the setMaxResults method in Retrieving contacts using query parameters.

Retrieving contacts using query parameters

The Contacts Data API lets you request a set of contacts that match specified criteria, such as requesting contacts created or updated in a given date range, or published by a particular author. To do this, you create a Query object and pass it to the ContactsService.getQuery() method.

For example, to send a date-range query, use the setUpdatedMin method of the Query object. The following code snippet prints the title of each contact updated after the given start time:

public static void printDateMinQueryResults(
    ContactsService myService, DateTime startTime) throws ServiceException,
    IOException {
  // Create query and submit a request
  URL feedUrl = new URL("https://www.google.com/m8/feeds/contacts/liz@gmail.com/full");
  Query myQuery = new Query(feedUrl);
  myQuery.setUpdatedMin(startTime);
  ContactFeed resultFeed = myService.query(myQuery, ContactFeed.class);

  // Print the results
  System.out.println(resultFeed.getTitle().getPlainText() +
      " contacts updated on or after "
      + startTime);
  for (int i = 0; i < resultFeed.getEntries().size(); i++) {
    ContactEntry entry = resultFeed.getEntries().get(i);
    System.out.println("\t" + entry.getTitle().getPlainText());
    System.out.println("\t" + entry.getUpdated().toStringRfc822());
  }
}

Notice that the Query object is constructed using the same contact feed URL used to retrieve contacts.

The Contacts Data API supports the following Query methods:

setMaxResults
Set the maximum number of entries to return. If you want to receive all of the contacts, rather than only the default maximum, you can specify a very large number for this property.
setStartIndex
Set the 1-based index of the first result to be retrieved (for paging).
setUpdatedMin
Set the lower bound on entry update dates.
setStringCustomParameter("showdeleted","true")
Include deleted contacts in the returned contacts feed. Deleted contacts are shown as entries that contain nothing but an <atom:id> element and a <gd:deleted> element. (Google retains placeholders for deleted contacts for 30 days after deletion; during that time, you can request the placeholders using the showdeleted query parameter.)
setStringCustomParameter("orderby","lastmodified")
Sort the returned contacts by last-modified date.
setStringCustomParameter("sortorder", direction)
Set sorting order direction. direction can be either "ascending" or "descending".
setStringCustomParameter("group", groupId)
Set group id.

Note: To track incremental changes to a contact list, do the following: When you send a request for a feed, keep track of the value of the feed's <updated> element. Then you can later retrieve only the contacts that have changed since the previous request by setting updated-min to that <updated> value, and setting showdeleted to true.

For more information about query parameters, see the Contacts Data API Reference Guide and the Google Data APIs Reference Guide. In particular, there is no support for full-text queries or locating a contact by email address.

Note: By default, the entries in a feed are not ordered.

Retrieving a photo for a contact

Sample code downloading a photo:

public static void downloadPhoto(ContactEntry entry, ContactsService service)
    throws ServiceException, IOException {
  Link photoLink = entry.getContactPhotoLink();
  if (photoLink != null) {
    InputStream in = service.getStreamFromLink(photoLink);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    RandomAccessFile file = new RandomAccessFile(
        "/tmp/" + entry.getSelfLink().getHref().substring(
         entry.getSelfLink().getHref().lastIndexOf('/') + 1), "rw");
    byte[] buffer = new byte[4096];
    for (int read = 0; (read = in.read(buffer)) != -1;
        out.write(buffer, 0, read));
    file.write(out.toByteArray());
    file.close();
  }
}

Updating contacts

To update an existing contact, first retrieve the entry you want to update, modify it, and then send it to the server using the update method. The following code snippet modifies a contact's name, assuming that you've already retrieved the contact from the server.

Note: In the underlying XML, the contact's name is stored in the <atom:title> element. Thus, the Java client library uses the setTitle method to set the contact's name.

public static ContactEntry updateContactName(
    ContactsService myService, ContactEntry entryToUpdate, String newName)
    throws ServiceException, IOException {
  entryToUpdate.setTitle(new PlainTextConstruct(newName));
  URL editUrl = new URL(entryToUpdate.getEditLink().getHref());
  return myService.update(editUrl, entryToUpdate);
}

The above code returns a newly-updated ContactEntry. To update any other properties, simply set them in the ContactEntry object before calling update.

Note: If you try to update a contact using an outdated ETag (that is, if the contact has been updated by another client since you retrieved it), you'll receive an HTTP 412 Precondition Failed status code.

Photo management

Updating a photo is similar to adding a photo, but requires to provide the ETag of the current photo.

  public static void updateContactPhoto(ContactEntry entry, ContactsService service, byte[] photoData)
      throws ServiceException, IOException {
    Link photoLink = entry.getContactPhotoLink();
    URL photoUrl = new URL(photoLink.getHref());

    GDataRequest request = service.createRequest(GDataRequest.RequestType.UPDATE,
        photoUrl, new ContentType("image/jpeg"));

    request.setEtag(photoLink.getEtag());

    OutputStream requestStream = request.getRequestStream();
    requestStream.write(photoData);

    request.execute();
  }

To delete a photo for a contact, you can execute a code snippet like this one:

  public static void deleteContactPhoto(ContactEntry entry, ContactsService service)
      throws ServiceException, IOException {
    Link photoLink = entry.getContactPhotoLink();
    URL photoUrl = new URL(photoLink.getHref());
    service.delete(photoUrl, photoLink.getEtag());
  }

The examples above assume that the photo currently exists, and do not verify existence of the ETags. A realistic application would probably need to do that.

Deleting contacts

To delete a contact, just call the contact entry's delete method:

public static void deleteContact(ContactEntry entryToDelete)
    throws ServiceException, IOException {
  entryToDelete.delete();
}

Note: To update existing contacts, see Updating contacts; don't update by deleting contacts and then re-adding them.

Creating contact groups

You can use the Java client library to publish new contact group entries.

Here's an example of how to publish a new contact group:

public static ContactGroupEntry createContactGroup(ContactsService service,
    String name, String notes, ExtendedProperty additionalInfo)
    throws ServiceException, IOException {
  // Create the entry to insert
  ContactGroupEntry group = new ContactGroupEntry();
  group.setTitle(new PlainTextConstruct(name));

  group.addExtendedProperty(additionalInfo);

  // Ask the service to insert the new entry
  URL postUrl = new URL("https://www.google.com/m8/feeds/groups/liz@gmail.com/full");
  return service.insert(postUrl, group);
}

First, create a ContactGroupEntry object and set a name and other attributes for the contact group. Then use the ContactsService object to insert the contact group. The insert method takes the service's POST URL as a parameter. The method returns the entry as it was stored by the server. The entry returned is the entry you sent extended with elements added by the server, such as a contact group ID.

If your request fails for some reason, Google may return a different status code. For information about the status codes, see the Google Data API protocol reference document.

System groups

Besides the user-created contact groups, the Contacts API provides several predefined so-called system groups. These groups resemble closely the regular contact groups, but there are several differences:

  • System groups are always there for every account: they cannot be deleted, and it is not possible to create new ones. It is also impossible to update them, for example by changing their name.
  • Contact group entries of system groups don't have a rel="edit" link.
  • Their entries have a special property whose presence indicates that the group is a system one. The property contains an id attribute. This system group id can be used to identify a particular system group.

The current version of the Contacts API exposes 4 system groups:

  • The My Contacts group, intended to contain all the contacts that are important for the user. Its system group id is "Contacts".
  • The Friends, Family, and Coworkers groups, whose intended use is obvious.

The values of the system group ids corresponding to these groups can be found in the Reference Guide for the Contacts Data API.

Note: The system group id of the My Contacts group is "Contacts".

Retrieving contact groups

Retrieving all contact groups

Sample code to retrieve the user's contact groups:

public static void printAllGroups(ContactsService myService)
      throws ServiceException, IOException {
    // Request the feed
    URL feedUrl = new URL("https://www.google.com/m8/feeds/groups/liz@gmail.com/full");
    ContactGroupFeed resultFeed = myService.getFeed(feedUrl, ContactGroupFeed.class);
    // Print the results
    System.out.println(resultFeed.getTitle().getPlainText());

    for (int i = 0; i < resultFeed.getEntries().size(); i++) {
      ContactGroupEntry groupEntry = resultFeed.getEntries().get(i);
      System.out.println("Id: " + groupEntry.getId());
      System.out.println("Group Name: " + groupEntry.getTitle().getPlainText());
      System.out.println("Last Updated: " + groupEntry.getUpdated());
      System.out.println("Extended Properties:");
      for (ExtendedProperty property : groupEntry.getExtendedProperties()) {
        if (property.getValue() != null) {
          System.out.println("  " + property.getName() + "(value) = " +
              property.getValue());
         } else if (property.getXmlBlob() != null) {
          System.out.println("  " + property.getName() + "(xmlBlob) = " +
              property.getXmlBlob().getBlob());
        }
      }
      System.out.println("Self Link: " + groupEntry.getSelfLink().getHref());
      if (!groupEntry.hasSystemGroup()) {
        // System groups do not have an edit link
        System.out.println("Edit Link: " + groupEntry.getEditLink().getHref());
        System.out.println("ETag: " + groupEntry.getEtag());
      }
      if (groupEntry.hasSystemGroup()) {
        System.out.println("System Group Id: " +
            groupEntry.getSystemGroup().getId());
      }
   }
}

In the output of the above code, the system groups will be interspersed with the regular groups

Retrieving contact groups using query parameters

The Contacts Data API supports for contact groups the same Query methods as allowed for contacts, except for the setCustomParameter("group", groupID).

Sample code for contact groups restricted with set-updated-min method:

public static void printDateMinQueryResults(
    ContactsService myService, DateTime startTime) throws ServiceException,
    IOException {
  // Create query and submit a request
  URL feedUrl = new URL("https://www.google.com/m8/feeds/groups/liz@gmail.com/full");
  Query myQuery = new Query(feedUrl);
  myQuery.setUpdatedMin(startTime);
  ContactGroupFeed resultFeed = myService.query(myQuery, ContactGroupFeed.class);

  // Print the results
  System.out.println(resultFeed.getTitle().getPlainText() +
      " contact groups updated on or after "
      + startTime);
  for (int i = 0; i < resultFeed.getEntries().size(); i++) {
    ContactGroupEntry entry = resultFeed.getEntries().get(i);
    System.out.println("\t" + entry.getTitle().getPlainText());
    System.out.println("\t" + entry.getUpdated().toStringRfc822());
  }
}

Updating contact groups

To update an existing contact group, first you retrieve the entry you want to update, then you modify it, and then you send it to the server using the update method. The following code snippet modifies a contact group's name, assuming that you've already retrieved the group from the server.

public static ContactGroupEntry updateContactGrpupName(
    ContactsService myService, ContactGroupEntry entryToUpdate, String newName)
    throws ServiceException, IOException {
  entryToUpdate.setTitle(new PlainTextConstruct(newName));
  URL editUrl = new URL(entryToUpdate.getEditLink().getHref());
  return myService.update(editUrl, entryToUpdate);
}

The above code returns a ContactGroupEntry containing the entire newly-updated group. To update any other properties, simply set them in the ContactGroupEntry object before calling update.

Note: If you try to update a contact group using an outdated ETag (that is, if the group has been updated by another client since you retrieved it), you'll receive an HTTP 412 Precondition Failed status code.

System groups cannot be updated.

Deleting contact groups

Deleting a contact group can look like this:

public static void deleteContactGroup(ContactGroupEntry groupToDelete)
    throws ServiceException, IOException {
  groupToDelete.delete();
}

Note: To update existing contact groups, see Updating contact groups; don't update by deleting contact groups and then re-adding them.

System groups cannot be deleted.

Back to top

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.