Google Calendar Data API Developer's Guide: JavaScript

  
  
  
  
  
 

This document describes how to use the JavaScript client library to send Google data API ("GData") queries and interpret returned responses.

Google provides a set of client libraries, in a variety of programming languages, for interacting with services that have data APIs. Using these libraries, you can construct GData requests, send them to a service, and receive responses.

This document provides some general information about using the JavaScript client library, along with a set of examples of common uses.

Contents

Audience

This document is intended for JavaScript programmers who want to write client applications that can interact with GData services.

This document assumes that you understand the general ideas behind the Google data APIs protocol. It also assumes that you know how to program in JavaScript.

For reference information about the classes and methods provided by the client library, see the JavaScript client library API reference.

This document is designed to be read in order; each example builds on earlier examples.

Terms of use

You agree to abide by the Google JavaScript Client Library Terms of Use when using the JavaScript client library.

Data model and control flow overview

The JavaScript client library uses a set of classes to represent the elements used by the Google data APIs.

Note: The underlying representation of the data is JSON, but the client library provides an abstraction layer so you don't have to work with the JSON data directly. If you want to work directly with JSON, without the client library, see Using JSON with Google Data APIs.

The library provides methods that let you asynchronously send data to and receive data from a service that has a data API. For example, the google.gdata.calendar.CalendarService.getEventsFeed() method sends a request for a feed to Google Calendar. One of the parameters you pass is a continuation function, also known as a callback; the service returns the feed, in JSON format, by calling the continuation function. The client can then call various get methods to use the data in the form of JavaScript objects.

To add a new entry, you create the entry using the client library's classes and methods, then call the feed.insertEntry() method to send the new entry to the service. Again you provide a continuation function, which the service calls when the entry has been successfully added.

If you're new to JavaScript, the control flow may be a little confusing. After calling a method like getEventsFeed() or insertEntry(), in most cases your script ends. Execution resumes in the continuation function when the service returns the requested data. Therefore, anything that your client does to the returned data should be done in the continuation function, or called from that function. You may need to make some variables global in order to use them in multiple functions.

For more information about this style of programming, see "Continuation-passing style" in Wikipedia.

About supported environments

Currently, we only support JavaScript client applications that run in a web page in a browser. Currently supported browsers are Firefox 1.5 and higher, and Internet Explorer 6.0 and higher.

The JavaScript client library handles all communication with the service's server. If you're an experienced JS developer, you may be thinking, "But what about the same origin policy?" The JavaScript client library allows your client to send GData requests from any domain while remaining compliant with the browser security model.

Sample client applications

To see the JavaScript client library in action, visit our samples page.

Tutorial and examples

The following examples show how to send various requests to Google Calendar using the JavaScript client library.

Obtaining a data API key

To acquire the JavaScript client library, you need a developer key. To obtain one, go to the Google data API key signup page, read the terms of service, and enter your website's URL. The signup page provides you with a key, which is an alphanumeric string that your client uses to identify itself to Google when the client requests the client library.

A key is associated with a website. If you want to use the JavaScript client library on another site, you should obtain another key for that site. More specifically, a key is associated with the URL that you enter on the signup page; the key applies to all URLs under the domain or directory that you specify.

Note: The Google data API key for a given domain is the same as the Google Maps API key for that domain. If you already have a Google Maps API key for your domain, you can use that key rather than going through the data API key signup page.

Acquiring the library

Before your client can use the client library, the client has to request the client library code from the server.

Start by using a <script> tag in the <head> section of your HTML document to fetch the Google AJAX API loader:

<script type="text/javascript"
  src="http://www.google.com/jsapi?key=developer_key">
</script>

Where developer_key is the key you obtained from the signup page.

To acquire the GData client library after fetching the loader, use the following line in your JavaScript setup code, which must be called from the <head> section of your HTML document (or from a JavaScript file that's included using a <script> tag in the <head> section of your HTML document):

google.load("gdata", "1");

The second parameter to google.load() is the requested version number of the JavaScript client library.  Our version numbering scheme is modeled after the one used by the Google Maps API.  We recommend specifying version "1", which automatically returns the second-to-last revision of major version 1.  If you want to test your client with the very latest version of the client library, specify version "1.x".

Based on the feedback we receive from developers, we will occasionally declare a certain version of the client library to be "stable."  To use the latest stable version of the library, specify version "1.s"; however, that version may not have the latest features.

If you want a specific version of the library, you can specify a major and minor revision number, such as "1.0".

After you've called google.load(), you have to tell the loader to wait until the page finishes loading and then call your code:

google.setOnLoadCallback(getMyFeed);

Where getMyFeed() is a function defined in the next section of this document. Use this approach instead of having an onload handler attached to the <body> element.

Requesting an unauthenticated feed

To request an unauthenticated feed, add the following code to your JavaScript file, or to a <script> tag in your HTML file.

In the following code, getMyFeed() is called first (by the AJAX API loader, as described in the previous section).

It calls setupMyService() to create a connection (represented by a CalendarService object) to Google Calendar. We've pulled the service creation code out into a separate function for modularity; later, we'll modify the setupMyService() function, depending on your authentication choices.

After setting up the service, getMyFeed() calls the client library's getEventsFeed() method to request the feed.

We're specifying the feed URL in a global variable so that it can be used in later functions. In this example, we're using the public (unauthenticated) feed URL for a user named liz@gmail.com.

var feedUrl =
  "http://www.google.com/calendar/feeds/liz@gmail.com/public/full";

function setupMyService() {
  var myService =
    new google.gdata.calendar.CalendarService('exampleCo-exampleApp-1');
  return myService;
}

function getMyFeed() {
  myService = setupMyService();
 
  myService.getEventsFeed(feedUrl, handleMyFeed, handleError);
}

Note that we're making myService a global variable, for ease of use in later functions.

To make the above code work in your own client, you have to use a real user's email address, for a Calendar account with a publicly shared calendar.

Note: When you create a new CalendarService object, the client library calls a method named google.gdata.client.init(), which checks that the browser the client is running in is supported, and validates the developer key. If there's an error, then the client library displays an error message to the user. If you want to handle this sort of error yourself, then you can explicitly call google.gdata.client.init(handleInitError) before you create the service, where handleInitError() is your function. If an init error occurs, then your function receives a standard Error object; you can do whatever you want with that object.

In the call to getEventsFeed(), the second argument is handleMyFeed, which is a callback function; see below. Google Calendar processes the request and then, if the request was successful, passes a "feed root" object containing the requested feed to the callback. A feed root is a container object that contains a feed.

The third argument to getEventsFeed() is an optional error-handling function; if the client library encounters an error, it calls the specified error handler instead of the success callback function. The object that the client library passes as the argument to the error handler is an instance of the JavaScript Error object, with an additional cause property.

Here are simple versions of the callback function and the error-handler:

function handleMyFeed(myResultsFeedRoot) {
  alert("This feed's title is: " +
    myResultsFeedRoot.feed.getTitle().getText());
}

function handleError(e) {
  alert("There was an error!");
  alert(e.cause ? e.cause.statusText : e.message);
}

We're handling errors by simply displaying them to the user; your client's error handler should probably be more sophisticated. In some contexts, there may be no cause specified, so in those cases our example error handler falls back to displaying the standard message property.

Note that since this code doesn't do authentication, you can use it only to get a public feed.

Authenticating

The JavaScript client library uses the AuthSub authentication system. For information about authentication, see the GData authentication overview document. The rest of this section assumes that you're familiar with the basics of how this system works.

Before using authentication with the sample code provided in this document, change the feed URL from public to private:

var feedUrl =
  "http://www.google.com/calendar/feeds/liz@gmail.com/private/full";

Authenticating in a web client with AuthSub

Here's a brief overview of what happens during the authentication process for a web-based JavaScript client:

  1. The client application calls the google.accounts.user.login() method provided by the client library, passing it a "scope" value that indicates which Google service to use. For Google Calendar, the scope is http://www.google.com/calendar/feeds.
  2. The client library sends the browser to Google's "Access Request" page, where the user can enter their credentials to log in to the service.
  3. If the user logs in successfully, then the AuthSub system sends the browser back to the web client's URL, passing along the authentication token.
  4. The JavaScript client library stores the token in a cookie and returns control to the client application's function that called google.accounts.user.login().
  5. When the client application subsequently calls client library methods that interact with Calendar, the client library automatically attaches the token to all requests.

Note: For the JavaScript client library to make authenticated Calendar requests in a web browser, your page must contain an image that's hosted at the same domain as your page. It can be any image, even a single-pixel transparent image, but there must be an image on the page. If you want the image to not appear on your page, you can use the style attribute of the <img> tag to position the image outside the rendering area. For example: style="position:absolute; top: -1000px;"

Here's the client-application code that handles logging in. In this example, we're replacing the setupMyService() function from the previous example with a new version that calls a login function.

function logMeIn() {
  scope = "http://www.google.com/calendar/feeds";
  var token = google.accounts.user.login(scope);
}

function setupMyService() {
  var myService =
    new google.gdata.calendar.CalendarService('exampleCo-exampleApp-1');
  logMeIn();
  return myService;
}

Tip: We strongly recommend that you provide a login button or other user input mechanism to prompt the user to start the login process manually. If, instead, you call google.accounts.user.login() immediately after loading, without waiting for user interaction, then the first thing the user sees on arrival at your page is a Google login page. If the user decides not to log in, then Google does not direct them back to your page; so from the user's point of view, they tried to visit your page but were sent away and never sent back. This scenario may be confusing and frustrating to users. Note that the example code above does call google.accounts.user.login() immediately after loading, to keep the example simple, but we don't recommend this approach for real-world client applications.

Note that you don't have to do anything with the variable named token; the client library keeps track of the token, so you don't have to.

The token remains valid until you revoke it by calling google.accounts.user.logout():

function logMeOut() {
  google.accounts.user.logout();
}

If you don't call logout(), then the cookie that stores the token lasts for two years, unless the user deletes it. The cookie is retained across browser sessions, so the user can close their browser and then reopen it and come back to your client and they'll still be logged in.

However, there are certain unusual circumstances in which a token can become invalid during a session. If Google Calendar rejects a token, your client should handle the error condition by calling logout() to remove the cookie containing the current token, and then calling login() again to acquire a new, valid token.

There are two other AuthSub methods that you may find useful in various contexts:

For details about using JavaScript to interact with AuthSub, including information on token management and on checkLogin() and getInfo(), see the Using "AuthSub" Authentication with the JavaScript Client Library document.

Inserting a new item

To create a new calendar event, continue execution from the earlier example by modifying the end of the handleMyFeed() function to call a new function:

function handleMyFeed(myResultsFeedRoot) {
  alert("This feed's title is: " +
    myResultsFeedRoot.feed.getTitle().getText());
  insertIntoMyFeed(myResultsFeedRoot);
}

In the new function, first use the CalendarEventEntry constructor to create the new entry. Then insert the entry, providing a callback for the service to call when the insertion is done.

function insertIntoMyFeed(feedRoot) {
  var newEntry = new google.gdata.calendar.CalendarEventEntry({
    authors: [
      {
        name: "Elizabeth Bennet",
        email: "liz@gmail.com"
      }
    ],
    title: {type: 'text', text: 'Tennis with Darcy'},
    content: {type: 'text', text: 'Meet for a quick lesson'},
    locations: [
      {
        rel: "g.event",
        label: "Event location",
        valueString: "Netherfield Park tennis court"
      }
    ],
    times: [
      {
        startTime:
          google.gdata.DateTime.fromIso8601("2007-09-23T18:00:00.000Z"),
        endTime:
          google.gdata.DateTime.fromIso8601("2007-09-23T19:00:00.000Z")
      }
    ]
    }
  );
  feedRoot.feed.insertEntry(newEntry, handleMyInsertedEntry, handleError);
}

Note that the name of each object property used in the constructor matches the name of the setter method used for that property. (Rather than, for example, matching the corresponding JSON field name.)

Also note that you can't just provide ISO 8601 date-and-time strings for startTime and endTime; you have to run such strings through the fromIso8601() method first.

The service returns a copy of the inserted entry as an entryRoot object, and passes that object to the callback:

function handleMyInsertedEntry(insertedEntryRoot) {
  alert("Entry inserted. The title is: " +
    insertedEntryRoot.entry.getTitle().getText());
  alert("The timestamp is: " +
    insertedEntryRoot.entry.getTimes()[0].startTime);
}

Requesting a specific entry

To request a specific entry, first modify the handleMyInsertedEntry() function to call a new entry-request function:

function handleMyInsertedEntry(insertedEntryRoot) {
  alert("Entry inserted. The title is: " +
    insertedEntryRoot.entry.getTitle().getText());
  alert("The timestamp is: " +
    insertedEntryRoot.entry.getTimes()[0].startTime);
  requestMySpecificEntry(insertedEntryRoot.entry.getSelfLink().getHref());
}

The following code lets you request a specific entry, given the entry's URI. In this context, we already have the entry; we're just requesting it again for demonstration purposes.

function requestMySpecificEntry(entryURI) {
  myService.getEventsEntry(entryURI, handleMySpecificEntry, handleError);
}

function handleMySpecificEntry(retrievedEntryRoot) {
  myEntryRoot = retrievedEntryRoot; // Global variable for later use
  alert("This entry's title is: " +
    retrievedEntryRoot.entry.getTitle().getText());
}

This example is essentially the same as the getEventsFeed() example, except that we're calling the service's getEventEntry() method to get a specific entry, and the URI is a little different—it uses "default" to refer to the main calendar for the authenticated user, and it has an entry ID at the end of it.

Also, we need to be able to use the retrieved entry later, so we're copying it into a global variable.

Searching entries

To perform a full-text search, first modify the handleMySpecificEntry() function to call a new search function:

function handleMySpecificEntry(retrievedEntryRoot) {
  myEntryRoot = retrievedEntryRoot; // Global variable for later use
  alert("This entry's title is: " +
    retrievedEntryRoot.entry.getTitle().getText());
  searchMyFeed();
}

Then retrieve the first match the search, using the following code:

function searchMyFeed() {
  var myQuery = new google.gdata.calendar.CalendarEventQuery(feedUrl);
  myQuery.setFullTextQuery("Tennis");
  myQuery.setMaxResults(10);
  myService.getEventsFeed(myQuery, handleMyQueryResults, handleError);
}

function handleMyQueryResults(myResultsFeedRoot) {
  if (myResultsFeedRoot.feed.getEntries()[0]) {
    alert("The first search-match entry's title is: " +
      myResultsFeedRoot.feed.getEntries()[0].getTitle().getText());
  }
  else {
    alert("There are no entries that match the search query.");
  }
}

Updating an item

To update an existing item, first add a line to the end of handleMyQueryResults() to call a new update function:

  updateMyEntry();

Then use the following code. In this example, we're changing the title of the previously retrieved entry (which was contained in the global object named myEntryRoot in an earlier example) from its old text ("Tennis with Darcy") to "Important meeting."

function updateMyEntry() {
  myEntryRoot.entry.getTitle().setText("Important meeting");
  myEntryRoot.entry.updateEntry(handleMyUpdatedEntry, handleError);
}

function handleMyUpdatedEntry(updatedEntryRoot) {
  alert("Entry updated. The new title is: " +
    updatedEntryRoot.entry.getTitle().getText());
}

As with all of the Calendar methods, the updateEntry() method automatically determines the correct edit URI to use in updating the entry, so you don't have to provide that URI explicitly.

Deleting an item

To delete the updated entry, first add a line to handleMyUpdatedEntry():

 deleteMyEntry(updatedEntryRoot);

Then use the following code:

function deleteMyEntry(updatedEntryRoot) {
  updatedEntryRoot.entry.deleteEntry(handleMyDeletedEntry, handleError);
}

function handleMyDeletedEntry() {
  alert("Entry deleted");
}

Again, the deleteEntry() method automatically determines the correct edit URI to use in deleting the entry.

Note that no entry is returned. If the callback is called, then we know the deletion was successful; if the deletion fails, then deleteEntry() calls handleError() instead of calling handleMyDeletedEntry().

Back to top

Last modified: