The Blogger Data API allows client applications to view and update Blogger content in the form of Google Data API feeds.
Your client application can use the Blogger Data API to create new blog posts, edit or delete existing blog posts, and query for blog posts that match particular criteria.
In addition to providing some background on the capabilities of the Blogger Data API, this document provides examples of basic Data API interactions using the JavaScript 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.
This document is intended for programmers who want to write JavaScript client applications that can interact with Blogger. It provides a series of examples of basic Data API interactions using the JavaScript client library.
For Blogger Data API reference information, see the Protocol reference guide. This document assumes that you understand the general ideas behind the Google Data APIs protocol and the data model and control flow used by the JavaScript client library. 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.
You agree to abide by the Google JavaScript Client Library Terms of Use when using the JavaScript client library.
Before you can write a JavaScript client application, you need to do some setup to acquire the library.
You may want to sign up for a Blogger account for testing purposes. Blogger uses Google Accounts, so if you already have a Google account, you're all set.
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 Google Data API requests from any domain while remaining compliant with the browser security model.
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"></script>
To acquire the Google Data API 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.x");
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. Here are the possible version numbers and what they mean:
"1""1.x""1.s""1.0", "1.1", etcAfter 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(getMyBlogFeed);
Where getMyBlogFeed() is a function that we'll define in a later section of this document. Use this approach instead of having an onload handler attached to the <body> element.
You can access both public and private feeds using the Blogger Data API. Public feeds don't require any authentication, but they are read-only. If you want to modify blogs, then your client needs to authenticate before requesting private feeds.
The JavaScript client library uses the AuthSub authentication system. For more information about authentication with Google Data APIs in general, see the authentication documentation.
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 Blogger user; instead, the client obtains special AuthSub tokens that allow the client to act on a particular user's behalf.
Here's a brief overview of what happens during the authentication process for a web-based JavaScript client:
google.accounts.user.login() method provided by the client library, passing it a "scope" value that indicates which Google service to use. For Blogger, the scope is "http://www.blogger.com/feeds".google.accounts.user.login().Note: For the JavaScript client library to make authenticated Blogger 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. We'll call the setupMyService() function from other code later.
function logMeIn() {
scope = "http://www.blogger.com/feeds";
var token = google.accounts.user.login(scope);
}
function setupMyService() {
var myService =
new google.gdata.blogger.BloggerService('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. In the example code in this document, we'll be calling 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.
Note: When you create a new BloggerService object, the client library calls a method named google.gdata.client.init(), which checks that the browser the client is running in is supported. 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.
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 Blogger 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:
google.accounts.user.checkLogin(scope) tells you whether or not the browser currently has an authentication token for the given scope.google.accounts.user.getInfo() provides detailed information about the current token, for debugging use.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.
The Blogger Data API provides a feed that lists the blogs for a particular user; that feed is known as a "metafeed."
The following sample code is called by the Google AJAX API loader when the client library finishes loading, as specified earlier. This code sets up an authenticated service, then retrieves the metafeed and displays the title of the first blog in the list.
function getMyBlogFeed() {
myService = setupMyService();
var myBlogFeedUri = "http://www.blogger.com/feeds/default/blogs";
myService.getBlogFeed(myBlogFeedUri, handleMyBlogFeed, handleError);
}
function handleMyBlogFeed(myResultsFeedRoot) {
var firstBlog = myResultsFeedRoot.feed.getEntries()[0];
firstBlogID = firstBlog.getId().getValue();
alert("The first blog's title is: " +
firstBlog.getTitle().getText());
}
Note that we're making myService a global variable, for ease of use in later functions.
The specified URL is the default metafeed URL; it returns a list of blogs for the currently authenticated user. To access a feed for a different user, you can put the user's ID in place of default in the metafeed URL. The user's ID is the string of digits at the end of the user's profile URL (http://www.blogger.com/profile/userID).
After setting up the service, getMyBlogFeed() calls the client library's getBlogFeed() method to request the metafeed.
In the call to getBlogFeed(), the second argument is handleMyBlogFeed, which is a callback function. Blogger 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 getBlogFeed() 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's a simple version of the error handler:
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.
To retrieve a feed for a specific blog, continue execution from the previous example by modifying the end of the handleMyBlogFeed() function to call a new function, getBlogPostFeed():
function handleMyBlogFeed(myResultsFeedRoot) {
var firstBlog = myResultsFeedRoot.feed.getEntries()[0];
firstBlogID = firstBlog.getId().getValue();
alert("The first blog's title is: " +
firstBlog.getTitle().getText());
feedUri = firstBlog.getEntryPostLink().getHref();
myService.getBlogPostFeed(feedUri, handleMyBlogPostFeed, handleError);
}
We're specifying the feed URL in a global variable so that it can be used in later functions.
The first parameter to getBlogPostFeed()is the feed URI of the blog; the second is another callback function:
function handleMyBlogPostFeed(myResultsFeedRoot) {
alert("The blog's title is: " +
myResultsFeedRoot.feed.getTitle().getText());
}
When you create a new blog post, you can choose whether to mark it as a draft or not.
To create a new blog entry, continue execution from the earlier example by modifying the end of the handleMyBlogPostFeed() function to call a new function:
function handleMyBlogPostFeed(myResultsFeedRoot) {
alert("The blog's title is: " +
myResultsFeedRoot.feed.getTitle().getText());
insertIntoMyFeed(myResultsFeedRoot);
}
In the new function, first use the BlogPostEntry constructor to create the new entry. Then insert the entry, providing a callback for the service to call when the insertion is done.
Note: The class name for a "post" (an entry) in a blog is BlogPostEntry; the class name for an entry in the list-of-blogs metafeed is BlogEntry. A BlogPostEntry represents a blog post; a BlogEntry represents a blog. It's easy to confuse the two names, so make sure you're using the one you intended.
function insertIntoMyFeed(feedRoot) {
var newEntry = new google.gdata.blogger.BlogPostEntry({
authors: [
{
name: "Elizabeth Bennet",
email: "liz@gmail.com"
}
],
title: {type: 'text', text: 'Quite disagreeable'},
content: {type: 'text', text: 'I met Mr. Bingley\'s friend Mr. Darcy this evening.
I found him quite disagreeable.'}
}
);
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.)
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());
}
To mark a blog post as a draft while creating it, use the setControl() method. Specifically, add the following code to the insertIntoMyFeed() function, before calling insertEntry():
newEntry.setControl({
draft: {value: google.gdata.Draft.VALUE_YES}
}
);
You can turn an existing draft blog post into a published post by retrieving the draft post, setting the value to VALUE_NO, and then updating the post. We'll cover retrieving and updating posts in subsequent sections of this document.
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());
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.getBlogPostEntry(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 getBlogPostFeed() example, except that we're calling the service's getBlogPostEntry() method to get a specific entry, and the URI is a little different—it uses "default" to refer to the main blog 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.
The Google Data API lets you request a set of entries that match specified criteria, such as requesting blog posts created in a given date range, or published by a particular author. To do this you create a BlogPostQuery object and pass it to the getBlogPostFeed() method. For example, to send a date-range query, use the setPublishedMin() and setPublishedMax() methods of the BlogPostQuery object.
To perform a query with query parameters using the sample code, first modify the handleMySpecificEntry() function to call a new query function:
function handleMySpecificEntry(retrievedEntryRoot) {
myEntryRoot = retrievedEntryRoot; // Global variable for later use
alert("This entry's title is: " +
retrievedEntryRoot.entry.getTitle().getText());
queryMyFeed();
}
The following code prints the title of each blog post updated between the given startTime and endTime.
function queryMyFeed() {
var myQuery = new google.gdata.blogger.BlogPostQuery(feedUri);
var myStartDate = new Date("Oct 8, 2007");
var myEndDate = new Date("Oct 12, 2007");
startTime = new google.gdata.DateTime(myStartDate);
endTime = new google.gdata.DateTime(myEndDate);
myQuery.setPublishedMin(startTime);
myQuery.setPublishedMax(endTime);
myService.getBlogPostFeed(myQuery, handleMyQueryResults, handleError);
}
function handleMyQueryResults(myResultsFeedRoot) {
var myFeed = myResultsFeedRoot.feed;
alert(myFeed.getTitle().getText() + " posts between "
+ google.gdata.DateTime.toIso8601(startTime) + " and "
+ google.gdata.DateTime.toIso8601(endTime));
for (var i = 0; i < myFeed.getEntries().length; i++) {
var thisEntry = myFeed.getEntries()[i];
alert(thisEntry.getTitle().getText());
alert(google.gdata.DateTime.toIso8601(thisEntry.getPublished().getValue()));
}
}
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 ("Quite disagreeable") to "Very agreeable."
function updateMyEntry() {
myEntryRoot.entry.getTitle().setText("Very agreeable");
myEntryRoot.entry.updateEntry(handleMyUpdatedEntry, handleError);
}
function handleMyUpdatedEntry(updatedEntryRoot) {
alert("Entry updated. The new title is: " +
updatedEntryRoot.entry.getTitle().getText());
}
As with all of the Blogger 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.
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().
The Blogger Data API allows for creating, retrieving, and deleting comments. Updating comments is not supported (nor is it available in the web interface).
To post a comment, create a BlogCommentEntry object and insert it as follows.
This function relies on receiving a blog post entryRoot, so if you want to integrate it into the sample code in this document, you have to call insertMyComment() before you delete the entry.
The first step is to parse the blog post's ID, which is a long string containing two numerical values, one of which identifies the blog and the other of which identifies the blog post. Then construct the comment feed URI using both of those numbers.
Then create a new comment and insert it. As usual, the insertion returns the inserted comment.
function insertMyComment(entryRoot) {
var blogPostEntryID = entryRoot.entry.getId().getValue();
var blogPostEntryIDPattern = new RegExp(/blog-(\d+)\.post-(\d+)/);
var match = blogPostEntryIDPattern.exec(blogPostEntryID);
blogPostCommentFeedUri = "http://www.blogger.com/feeds/" +
match[1] + "/" + match[2] + "/comments/default";
var newComment = new google.gdata.blogger.BlogCommentEntry({
content: {type: 'text', text: 'Darcy FTW!'}
}
);
myService.insertEntry(blogPostCommentFeedUri, newComment,
handleMyInsertedComment, handleError);
}
function handleMyInsertedComment(commentEntryRoot) {
alert("The comment's title is: " +
commentEntryRoot.entry.getTitle().getText());
}
Note: Currently, you can only post comments to a blog owned by the authenticated user.
We're making blogPostCommentFeedUri a global variable, for later use.
You can retrieve the comments for a particular post from the post comments feed URL.
First add a line to the end of handleMyInsertedComment() to call a new function:
retrieveMyComments();
We've already determined the comment feed URI, so we pass that to getBlogCommentFeed():
function retrieveMyComments() {
myService.getBlogCommentFeed(blogPostCommentFeedUri,
handleMyBlogCommentFeed, handleError);
}
function handleMyBlogCommentFeed(myResultsFeedRoot) {
var firstComment = myResultsFeedRoot.feed.getEntries()[0];
alert("The first comment's title is: " +
firstComment.getTitle().getText());
}
Alternatively, you can get the comments from all posts by using the blog's comments feed URL:
http://www.blogger.com/feeds/blogID/comments/default
To delete a comment, pass the comment's edit URL to the deleteEntry() method on your BloggerService object.
First add a line to the end of handleMyBlogCommentFeed() to call a new function:
deleteMyComment(firstComment);
Then determine the appropriate URI and call deleteEntry():
function deleteMyComment(commentToDelete) {
var deleteUri = commentToDelete.getEditLink().getHref();
myService.deleteEntry(deleteUri, handleMyDeletedComment, handleError);
}
function handleMyDeletedComment() {
alert("Comment deleted");
}