Google Documents List API version 3.0
Important: Version 3 of the Google Documents List API has been officially deprecated as of September 14, 2012. It will continue to work as per our deprecation policy, but we encourage you to move to the Google Drive API.
The Google Documents List API allows client applications to view and manipulate files in a user's Documents List. Your application can use this API to store files and to integrate the Google Docs experience.
Introduction
This guide discusses how to use the Google Documents List API version 3.0.
What can this API do?
The Google Documents List API allows developers to create, retrieve, update, and delete Google Docs (including but not limited to text documents, spreadsheets, presentations, and drawings), files, and collections. It also provides some advanced features like resource archives, Optical Character Recognition, translation, and revision history.
You will find this API useful if you need to store data in the cloud, perform resource management, convert document formats, etc. All interactions with the API require a valid Google Account, which can be a "consumer" account (e.g. Gmail), or a Google Apps account.
Audience
This developer's guide is intended for software developers needing a technical reference for using the Google Documents List API. The information you find in this guide is written by Google engineers, and is authoritative on how the API behaves.
Terminology used in this guide
Throughout this guide, we refer to a series of terms like document or file, which we intend to have specific meanings.
- document
- Any item maintained by Google Docs that is hosted in a native Google Docs format. This can include a text document, spreadsheet, presentation, or drawing. A document is created by either creating an empty Google Doc in the web interface or by using the API to upload an existing file. When you upload something like a Microsoft Excel® file, if you opt to convert it to a Google Doc, then it is considered a "document" in this guide. If you do not convert it when you upload, then it is considered a "file" (see below).
- file
- Any item maintained by Google Docs that is not hosted in the native format. This could include a PDF file, MP3 file, MPEG file, TXT file, etc. A file is created by uploading an item to Google Docs, and not converting it to the native Google Docs format. That is to say, you could have an unconverted Microsoft Excel file hosted in Google Docs. If you were to do this though, the file would not be available for conversion to other formats, full text search, or many other features provided by this API.
- collection
- A container of other documents, files, or collections. These were previously named folders. In order to avoid issues with backward-compatibility, we have not renamed folders to collections in the API protocol. The API still returns resource IDs with a type of folder.
- resource
- Any item maintained by the API, including documents, files, and collections.
- resource ID
- A unique identifier for each resource. This is usually of the format [type]:[id], e.g. document:12345. Throughout this guide, if not specified, a typed resource ID should be assumed.
- untyped resource ID
- A resource ID, without the type prefix. Given the previous example, an untyped resource ID would be 12345.
Should I use version 3 of the API?
There are currently three versions of the Google Documents List API. Version 1 has been deprecated, and should not be used. Version 2 is no longer recommended.
Version 3 of the API (the version you're currently reading about) has many more features than versions 1 or 2. We highly recommend that you use version 3 if at all possible.
Additional resources, information about this guide
Occasionally, we make a mistake in this documentation, or unknowingly break a feature that you depend on.
If this has happened to you, sorry! You can help us fix the issue by posting in the forum or by filing a bug. We appreciate your help!
Setting up your client library
A number of client libraries are provided in various languages. These client libraries make it easier to interact with the Documents List API.
This section is not relevant to applications using the Documents List API at the protocol level, but all application developers should strongly consider using a GData client library to interact with the API.
Java
The Java client library is maintained in an open-source project on Google Project hosting. The Java library itself is distributed as a ZIP file, containing a number of JARs that applications can import in order to gain access to the library.
The Java client library requires JDK 5.0 or greater. The latest version of the Oracle JDK is available from http://www.oracle.com/technetwork/java/index.html.
Unfortunately, due to restrictive licensing, we cannot at this time just give developers a ZIP of all JARs required to interact with the API. Some of the JARs are not available without additional license agreements. Because of this, some of the JARs must be downloaded individually. We sincerely apologize for this inconvenience.
To setup a development environment for working with the Documents List API, perform the following steps.
Download the latest
gdata-src.java-*.zip
file from the project's Downloads page. Replace*
in this case with something like1.46.0
.Extract the ZIP file into a new directory.
unzip gdata-src.java-1.46.0.zip -d ./gdata-java-client
Copy the JARs from
gdata-java-client/gdata/java/lib
into a directory included in the application's classpath.cp gdata-java-client/gdata/java/lib/* /path/to/application/lib
Copy the JARs from
gdata-java-client/gdata/java/deps
into the application's classpath.cp gdata-java-client/gdata/java/deps/* /path/to/application/lib
Download the JavaMail API (version 1.4 or greater) from here. Extract the ZIP file and copy
mail.jar
to the application's classpath.unzip javamail1_4_4.zip -d javamail cp javamail/javamail-1.4.4/mail.jar /path/to/application/lib
If using the Oracle JDK version 1.5, download the JavaBeans Activation Framework from here. Extract the ZIP file and copy
activation.jar
to the application's classpath.unzip jaf-1_1_1.zip -d jaf cp jaf/jaf-1.1.1/activation.jar /path/to/application/lib
To implement any of the code discussed in this document, use the following class template.
import com.google.gdata.client.authn.oauth.*; import com.google.gdata.client.docs.*; import com.google.gdata.data.*; import com.google.gdata.data.batch.*; import com.google.gdata.data.docs.*; import com.google.gdata.util.*; import java.io.IOException; import java.net.*; import java.util.*; public class MyDocumentsListIntegration { public static void main(String[] args) throws AuthenticationException, MalformedURLException, IOException, ServiceException { // Application code here } }
Once the above template is in place, continue reading the rest of this document, applying the Java code samples as necessary.
.NET
The .NET client library is maintained in an open-source project on Google Project hosting. The .NET library itself is distributed as a MSI installer, containing a number of DLLs that applications can import in order to gain access to the library.
The .NET client library requires the .NET Framework 2.0 or greater.
To setup a development environment for working with the Documents List API, perform the following steps.
Download the latest
Google_Data_API_Setup_*.msi
file from the project's Downloads page. Replace*
in this case with something like1.9.0.0
.Run the installer and follow the instructions in the setup wizard.
To implement any of the code discussed in this document, use the following class template.
using Google.GData.Client; using Google.GData.Documents; namespace MyDocumentsListIntegration { class Program { static void Main(string[] args) { // Application code here } } }
Once the above template is in place, continue reading the rest of this document, applying the .NET code samples as necessary.
Authorizing requests
When your application requests non-public user data, it must include an authorization token. The token also identifies your application to Google.
About authorization protocols
We recommend using OAuth 2.0 to authorize requests.
The Google Documents List Data API also supports older authorization options, such as OAuth 1.0, AuthSub, or ClientLogin; however, in most cases we don't recommend using those other options. If your application already uses those options, we recommend migrating to OAuth 2.0 if possible.
If your application has certain unusual authorization requirements, such as logging in at the same time as requesting data access (hybrid) or domain-wide delegation of authority (2LO), then you cannot currently use OAuth 2.0 tokens. In such cases, you must instead use OAuth 1.0 tokens.
Authorizing requests with OAuth 2.0
Requests to the Google Documents List Data API for non-public user data must be authorized by an authenticated user.
The details of the authorization process, or "flow," for OAuth 2.0 vary somewhat depending on what kind of application you're writing. The following general process applies to all application types:
- When you create your application, you register it with Google. Google then provides information you'll need later, such as a client ID and a client secret.
- Activate the Google Documents List Data API in the Services pane of the Google APIs Console. (If it isn't listed in the Console, then skip this step.)
- When your application needs access to user data, it asks Google for a particular scope of access.
- Google displays an OAuth dialog to the user, asking them to authorize your application to request some of their data.
- If the user approves, then Google gives your application a short-lived access token.
- Your application requests user data, attaching the access token to the request.
- If Google determines that your request and the token are valid, it returns the requested data.
Some flows include additional steps, such as using refresh tokens to acquire new access tokens. For detailed information about flows for various types of applications, see Google's OAuth 2.0 documentation.
Here's the OAuth 2.0 scope information for the Google Documents List Data API:
https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/
To request access using OAuth 2.0, your application needs the scope information, as well as information that Google supplies during application registration (such as the client ID and/or the client secret).
Performing OAuth 2.0
.NET
The following example is copied from the google-gdata project's sample directory. It has been modified to accommodate the Documents List API, and is provided here for ease of reference.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
////////////////////////////////////////////////////////////////////////////
// STEP 1: Configure how to perform OAuth 2.0
////////////////////////////////////////////////////////////////////////////
// TODO: Update the following information with that obtained from
// https://code.google.com/apis/console. After registering
// your application, these will be provided for you.
string CLIENT_ID = "12345678.apps.googleusercontent.com";
// This is the OAuth 2.0 Client Secret retrieved
// above. Be sure to store this value securely. Leaking this
// value would enable others to act on behalf of your application!
string CLIENT_SECRET = "Gc0230jdsah01jqpowpgff";
// Space separated list of scopes for which to request access.
string SCOPE = "https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/";
// This is the Redirect URI for installed applications.
// If you are building a web application, you have to set your
// Redirect URI at https://code.google.com/apis/console.
string REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
////////////////////////////////////////////////////////////////////////////
// STEP 2: Set up the OAuth 2.0 object
////////////////////////////////////////////////////////////////////////////
// OAuth2Parameters holds all the parameters related to OAuth 2.0.
OAuth2Parameters parameters = new OAuth2Parameters();
// Set your OAuth 2.0 Client Id (which you can register at
// https://code.google.com/apis/console).
parameters.ClientId = CLIENT_ID;
// Set your OAuth 2.0 Client Secret, which can be obtained at
// https://code.google.com/apis/console.
parameters.ClientSecret = CLIENT_SECRET;
// Set your Redirect URI, which can be registered at
// https://code.google.com/apis/console.
parameters.RedirectUri = REDIRECT_URI;
////////////////////////////////////////////////////////////////////////////
// STEP 3: Get the Authorization URL
////////////////////////////////////////////////////////////////////////////
// Set the scope for this particular service.
parameters.Scope = SCOPE;
// Get the authorization url. The user of your application must visit
// this url in order to authorize with Google. If you are building a
// browser-based application, you can redirect the user to the authorization
// url.
string authorizationUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
Console.WriteLine(authorizationUrl);
Console.WriteLine("Please visit the URL above to authorize your OAuth "
+ "request token. Once that is complete, type in your access code to "
+ "continue...");
parameters.AccessCode = Console.ReadLine();
////////////////////////////////////////////////////////////////////////////
// STEP 4: Get the Access Token
////////////////////////////////////////////////////////////////////////////
// Once the user authorizes with Google, the request token can be exchanged
// for a long-lived access token. If you are building a browser-based
// application, you should parse the incoming request token from the url and
// set it in OAuthParameters before calling GetAccessToken().
OAuthUtil.GetAccessToken(parameters);
string accessToken = parameters.AccessToken;
Console.WriteLine("OAuth Access Token: " + accessToken);
////////////////////////////////////////////////////////////////////////////
// STEP 5: Make an OAuth authorized request to Google
////////////////////////////////////////////////////////////////////////////
// Initialize the variables needed to make the request
GOAuth2RequestFactory requestFactory =
new GOAuth2RequestFactory(null, "MyDocumentsListIntegration-v1", parameters);
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
service.RequestFactory = requestFactory;
// Make the request to Google
// See other portions of this guide for code to put here...
}
}
}
Authorizing requests with OAuth 1.0a
As with OAuth 2.0, the scope to request for OAuth 1.0a while working with the Documents List API is:
https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/
As mentioned previously, the Java client library does not currently support OAuth 2.0. Instead, to authorize with OAuth 1.0a, use the following code.
Performing 3-Legged OAuth 1.0a (OAuth 1.0a for Web Applications)
Java
The following example is copied from the gdata-java-client project's sample directory. It has been modified to accommodate the Spreadsheets API, and is provided here for ease of reference.
import com.google.gdata.client.authn.oauth.GoogleOAuthHelper;
import com.google.gdata.client.authn.oauth.GoogleOAuthParameters;
import com.google.gdata.client.authn.oauth.OAuthHmacSha1Signer;
import com.google.gdata.client.authn.oauth.OAuthRsaSha1Signer;
import com.google.gdata.client.authn.oauth.OAuthSigner;
import com.google.gdata.client.docs.*;
import com.google.gdata.data.Link;
import com.google.gdata.data.batch.BatchOperationType;
import com.google.gdata.data.batch.BatchStatus;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.data.docs.*;
import com.google.gdata.util.*;
import java.io.IOException;
import java.net.*;
import java.util.*;
public class MyDocumentsListIntegration {
public static void main(String[] args)
throws AuthenticationException, MalformedURLException, IOException, ServiceException {
////////////////////////////////////////////////////////////////////////////
// STEP 1: Configure how to perform OAuth 1.0a
////////////////////////////////////////////////////////////////////////////
boolean USE_RSA_SIGNING = false;
// TODO: Update the following information with that obtained from
// https://www.google.com/accounts/ManageDomains. After registering
// your application, these will be provided for you.
String CONSUMER_KEY = "yourappdomain.com";
// TODO: Replace this with base-64 encoded private key conforming
// to PKCS #8 standard, if and only if you will use RSA-SHA1
// signing. Otherwise, this is the OAuth Consumer Secret retrieved
// above. Be sure to store this value securely. Leaking this
// value would enable others to act on behalf of your application!
String CONSUMER_SECRET = "Gc0230jdsah01jqpowpgff";
// Space separated list of scopes for which to request access.
String SCOPES = "https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/";
////////////////////////////////////////////////////////////////////////////
// STEP 2: Set up the OAuth objects
////////////////////////////////////////////////////////////////////////////
// You first need to initialize a few OAuth-related objects.
// GoogleOAuthParameters holds all the parameters related to OAuth.
// OAuthSigner is responsible for signing the OAuth base string.
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters();
// Set your OAuth Consumer Key (which you can register at
// https://www.google.com/accounts/ManageDomains).
oauthParameters.setOAuthConsumerKey(CONSUMER_KEY);
// Initialize the OAuth Signer. If you are using RSA-SHA1, you must provide
// your private key as a Base-64 string conforming to the PKCS #8 standard.
// Visit http://code.google.com/apis/gdata/authsub.html#Registered to learn
// more about creating a key/certificate pair. If you are using HMAC-SHA1,
// you must set your OAuth Consumer Secret, which can be obtained at
// https://www.google.com/accounts/ManageDomains.
OAuthSigner signer;
if (USE_RSA_SIGNING){
signer = new OAuthRsaSha1Signer(CONSUMER_SECRET);
} else {
oauthParameters.setOAuthConsumerSecret(CONSUMER_SECRET);
signer = new OAuthHmacSha1Signer();
}
// Finally, create a new GoogleOAuthHelperObject. This is the object you
// will use for all OAuth-related interaction.
GoogleOAuthHelper oauthHelper = new GoogleOAuthHelper(signer);
////////////////////////////////////////////////////////////////////////////
// STEP 3: Get the Authorization URL
////////////////////////////////////////////////////////////////////////////
// Set the scope for this particular service.
oauthParameters.setScope(SCOPES);
// This method also makes a request to get the unauthorized request token,
// and adds it to the oauthParameters object, along with the token secret
// (if it is present).
oauthHelper.getUnauthorizedRequestToken(oauthParameters);
// Get the authorization url. The user of your application must visit
// this url in order to authorize with Google. If you are building a
// browser-based application, you can redirect the user to the authorization
// url.
String requestUrl = oauthHelper.createUserAuthorizationUrl(oauthParameters);
System.out.println(requestUrl);
System.out.println("Please visit the URL above to authorize your OAuth "
+ "request token. Once that is complete, press any key to "
+ "continue...");
System.in.read();
////////////////////////////////////////////////////////////////////////////
// STEP 4: Get the Access Token
////////////////////////////////////////////////////////////////////////////
// Once the user authorizes with Google, the request token can be exchanged
// for a long-lived access token. If you are building a browser-based
// application, you should parse the incoming request token from the url and
// set it in GoogleOAuthParameters before calling getAccessToken().
String token = oauthHelper.getAccessToken(oauthParameters);
System.out.println("OAuth Access Token: " + token);
System.out.println();
////////////////////////////////////////////////////////////////////////////
// STEP 5: Make an OAuth authorized request to Google
////////////////////////////////////////////////////////////////////////////
// Initialize the variables needed to make the request
URL feedUrl = new URL(variables.getFeedUrl());
System.out.println("Sending request to " + feedUrl.toString());
System.out.println();
DocsService service =
new DocsService("MyDocumentsListIntegration-v1");
// Set the OAuth credentials which were obtained from the step above.
service.setOAuthCredentials(oauthParameters, signer);
// Make the request to Google
// See other portions of this guide for code to put here...
////////////////////////////////////////////////////////////////////////////
// STEP 6: Revoke the OAuth token
////////////////////////////////////////////////////////////////////////////
System.out.println("Revoking OAuth Token...");
oauthHelper.revokeToken(oauthParameters);
System.out.println("OAuth Token revoked...");
}
}
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
////////////////////////////////////////////////////////////////////////////
// STEP 1: Configure how to perform OAuth 1.0a
////////////////////////////////////////////////////////////////////////////
// TODO: Update the following information with that obtained from
// https://www.google.com/accounts/ManageDomains. After registering
// your application, these will be provided for you.
string CONSUMER_KEY = "yourappdomain.com";
// This is the OAuth Consumer Secret retrieved
// above. Be sure to store this value securely. Leaking this
// value would enable others to act on behalf of your application!
string CONSUMER_SECRET = "Gc0230jdsah01jqpowpgff";
// Space separated list of scopes for which to request access.
string SCOPE = "https://docs.google.com/feeds/ https://docs.googleusercontent.com/ https://spreadsheets.google.com/feeds/";
////////////////////////////////////////////////////////////////////////////
// STEP 2: Set up the OAuth object
////////////////////////////////////////////////////////////////////////////
// OAuthParameters holds all the parameters related to OAuth.
OAuthParameters parameters = new OAuthParameters();
// Set your OAuth Consumer Key (which you can register at
// https://www.google.com/accounts/ManageDomains).
parameters.ConsumerKey = CONSUMER_KEY;
// Set your OAuth Consumer Secret, which can be obtained at
// https://www.google.com/accounts/ManageDomains.
parameters.ConsumerSecret = CONSUMER_SECRET;
// HMAC-SHA1 is the only signature method supported by the .NET library.
parameters.SignatureMethod = OAuthBase.HMACSHA1SignatureType;
////////////////////////////////////////////////////////////////////////////
// STEP 3: Get the Authorization URL
////////////////////////////////////////////////////////////////////////////
// Set the scope for this particular service.
parameters.Scope = SCOPE;
// This method also makes a request to get the unauthorized request token,
// and adds it to the oauthParameters object, along with the token secret
// (if it is present).
OAuthUtil.GetUnauthorizedRequestToken(parameters);
// Get the authorization url. The user of your application must visit
// this url in order to authorize with Google. If you are building a
// browser-based application, you can redirect the user to the authorization
// url.
string authorizationUrl = OAuthUtil.CreateUserAuthorizationUrl(parameters);
Console.WriteLine(authorizationUrl);
Console.WriteLine("Please visit the URL above to authorize your OAuth "
+ "request token. Once that is complete, press any key to "
+ "continue...");
Console.ReadLine();
////////////////////////////////////////////////////////////////////////////
// STEP 4: Get the Access Token
////////////////////////////////////////////////////////////////////////////
// Once the user authorizes with Google, the request token can be exchanged
// for a long-lived access token. If you are building a browser-based
// application, you should parse the incoming request token from the url and
// set it in OAuthParameters before calling GetAccessToken().
OAuthUtil.GetAccessToken(parameters);
string accessToken = parameters.Token;
Console.WriteLine("OAuth Access Token: " + accessToken);
////////////////////////////////////////////////////////////////////////////
// STEP 5: Make an OAuth authorized request to Google
////////////////////////////////////////////////////////////////////////////
// Initialize the variables needed to make the request
GOAuthRequestFactory requestFactory =
new GOAuthRequestFactory(null, "MyDocumentsListIntegration-v1", parameters);
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
service.RequestFactory = requestFactory;
// Make the request to Google
// See other portions of this guide for code to put here...
}
}
}
Authorizing requests with ClientLogin
ClientLogin allows applications to make requests to the Spreadsheets API using the username and application-specific password of a Google account. When using this mechanism, applications must take extreme caution when handling these credentials, as leaking the credentials could have severe consequences. Any application experiencing a security concern should immediately notify affected users.
To implement the ClientLogin mechanism, make an authorized request to the
Spreadsheets API, with the appropriate Authorization
header.
Protocol
Detailed information on implementing ClientLogin from a protocol perspective is available here.
When fetching a ClientLogin token for the Documents List API, be sure to use
the writely
service name.
Java
The following is a code sample in which a DocsService
object is
configured to use ClientLogin for authorization.
import com.google.gdata.client.docs.*;
import com.google.gdata.data.docs.*;
import com.google.gdata.util.*;
import java.io.IOException;
import java.net.*;
public class MyDocumentsListIntegration {
public static void main(String[] args)
throws AuthenticationException, MalformedURLException, IOException, ServiceException {
String USERNAME = "someuser@gmail.com";
String PASSWORD = "testing123";
DocsService service = new DocsService("MyDocumentsListIntegration-v1");
service.setUserCredentials(USERNAME, PASSWORD);
// TODO: See other portions of this guide for code to put here...
}
}
.NET
The following is a code sample in which a DocumentsService
object is
configured to use ClientLogin for authorization.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
string USERNAME = "someuser@gmail.com";
string PASSWORD = "testing123";
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
service.setUserCredentials(USERNAME, PASSWORD);
// TODO: See other portions of this guide for code to put here...
}
}
}
Specifying a version
Every request that you send using version 3 of the API must specify that it is a version 3 request (version 2 is currently the default if you do not specify a version). You can skip this section if you are using the Java, Python, or .NET client libraries provided by Google, because those libraries automatically use version 3 of the API.
To specify a version number, use the GData-Version
HTTP header. The value of
this header must be 3.0. The decimal and the zero are required.
GData-Version: 3.0
Alternatively, you can specify v=3
as a query parameter in the URL. This is
often needed when working behind a firewall that strips HTTP headers, or from
some JavaScript requests. Use of the HTTP header is recommended when possible.
https://docs.google.com/feeds/default/private/full?v=3
Handling API errors
The Documents List API utilizes HTTP response codes to inform clients of the success or failure of each request. Clients should use the HTTP response code to trigger error handling if necessary (many errors can be resolved by retrying the request after a short delay). This section discusses various API error responses, and how to best handle them.
Suggested methods for handling various API responses
The following list represents the majority of cases clients encounter when using the API. Developers witnessing a response or error not listed here should post in the forum.
HTTP status code | Description | Resolution |
---|---|---|
200 | A request succeeded. | No error handling necessary. |
201 | A resource has been successfully created. | No error handling necessary. |
302 | A request has been made to a resource's content link, and the requested data is on a different Google system. | Make the same request again, but against the URI given in the response's Location header. |
304 | A conditional `GET` of a resource is requested, and the resource is unchanged. | No error handling necessary. |
400 | A request has been made to a malformed URI. This error often impacts new
users of the API, who forget to specify the GData-Version: 3.0 header. |
Modify the implementation of the client to make the request again to the correct URI, or specify the appropriate version header. |
400 | A request has been made with a malformed XML body. This is often caused by clients manually generating XML for requests, and not specifying some required XML namespaces. All sample requests in this guide show needed XML namespaces. | Modify the implementation of the client to make the request again with valid XML. |
400 | A request has been made to upload a resource with content for conversion, but the conversion of the content failed. Reasons for conversion failure include the content being malformed, the content being well-formed but the API being unable to convert it, or conversion failing temporarily. | Implement exponential backoff. |
400 | An unexpected error has occurred with the request. The occurrence of this situation is rare and almost never happens. | Post in the forum. Before posting, please ensure the 400 response is not due to one of the reasons discussed above. |
401 | The given Authorization header is invalid, and the
request is not authorized to continue. |
Modify the implementation of the client to provide a valid Authorization header. Developers implementing OAuth for the first time often have this problem. It is recommended to use one of the provided API client libraries instead, which automate many authorization mechanisms. |
403 | The authorized user is not permitted to make the given request. For example, the authorized user is not a writer on a resource, and therefore may not update the resource's content. | Each client application must define an error handling strategy which fits their use case. It could make the request again as an authorized user, or add the already authorized user to the ACL of the resource. |
404 | The requested URI or resource does not exist. It is possible for this response to be given after a resource has been deleted. | Each client application must define an error handling strategy which fits their use case. This could involve modifying the implementation to correct the URI or request the correct resource. |
409, 412 | The requested change to a resource conflicts with another change made by another API client or in a Google web UI. | Fetch the resource, merge the conflicting changes, and make the request again with the latest ETag of the resource. Alternatively, force the change through, disregarding the other party's changes. Forcing the change through is described in Updating/changing documents and files. |
411 | A resumable upload request is made, but the Content-Length
of the content being uploaded is not specified. |
Modify the client implementation to make the request with a valid
Content-Length header. |
500 | An unexpected error has occurred in the API. | This is probably a severe error. This response code is intended to indicate a temporary failure, so implementing exponential backoff is a reasonable error handling strategy for clients. If the problem persists, please post in the forum. |
503 | The client has made too many requests recently, or the requested API
endpoint is temporarily unavailable. The API provides a minimum
time in seconds within a Retry-After header that
the client should wait before retrying the request. |
Implement exponential backoff. |
Implementing exponential backoff
Exponential backoff is the process of a client periodically retrying a failed request over an increasing amount of time. It is a standard error handling strategy for network applications. The Documents List API is designed with the expectation that clients which choose to retry failed requests do so using exponential backoff. Besides being "required", using exponential backoff increases the efficiency of bandwidth usage, reduces the number of requests required to get a successful response, and maximizes the throughput of requests in concurrent environments.
The flow for implementing simple exponential backoff is as follows.
- Make a request to the API
- Receive a response indicating to retry the request
- Wait 1 +
random_number_milliseconds
seconds - Retry request
- Receive a response indicating to retry the request
- Wait 2 +
random_number_milliseconds
seconds - Retry request
- Receive a response indicating to retry the request
- Wait 4 +
random_number_milliseconds
seconds - Retry request
- Receive a response indicating to retry the request
- Wait 8 +
random_number_milliseconds
seconds - Retry request
- Receive a response indicating to retry the request
- Wait 16 +
random_number_milliseconds
seconds - Retry request
- Stop. Report or log an error.
In the above flow, random_number_milliseconds
is a random number of
milliseconds less than or equal to 1000. This is necessary to avoid certain
lock errors in some concurrent implementations. random_number_milliseconds
must
be redefined after each wait.
If the API response includes a Retry-After
header providing a
minimum wait time in seconds, clients should wait
max(retry_after, computed_wait_time)
.
The algorithm is set to terminate when n is 5. This ceiling is in place only to stop clients from retrying infinitely, and results in a total delay of around 32 seconds before a request is deemed "an unrecoverable error".
The following Python code is an implementation of the above flow for recovering from errors when pulling the resources feed.
import random
import time
import gdata.client
def GetResourcesWithExponentialBackoff(client):
"""Gets all of the resources for the user authorized on the given client.
Args:
client: gdata.docs.client.DocsClient authorized for a user.
Returns:
gdata.docs.data.ResourceFeed representing Resources found in the request.
"""
for n in range(0, 5):
try:
response = client.GetResources()
return response
except gdata.client.RequestError, error:
computed_time = (2 ** n) + (random.randint(0, 1000) / 1000)
time.sleep(max(error.headers.get('Retry-After'), computed_time))
except:
time.sleep((2 ** n) + (random.randint(0, 1000) / 1000))
print "There has been an error, the request never succeeded."
return None
Resource IDs explained
Every resource has a resource ID. As mentioned in the Terminology section, resource IDs have two forms: typed and untyped.
In an XML or JSON response from the API, the gd:resourceId
element will
always be a typed resource ID, like document:12345
.
The types of typed resource IDs can include but are not limited to:
- document (text document)
- drawing
- file
- folder
- presentation
- spreadsheet
In a URL referring to an individual resource, you will sometimes see an untyped resource ID, like 12345.
Using Google Apps administrative access to impersonate other domain users
Usually, requests sent to the Documents List API are of the form:
https://docs.google.com/feeds/default/...
In this case, default indicates to the API that it should act as the currently
authorized user (the default user). For 3-Legged OAuth, AuthSub, and
ClientLogin, it is obvious who the currently authorized user is, because the
authorization token is only valid for a single user. When using 2-Legged OAuth,
the authorized user for a request is specified by the xoauth_requestor_id
URL
parameter. This is only supported for active (non-suspended) users. If a user
is suspended, it is not possible to authorize requests as that specific user
via a URL that specifies default.
Administrative users may make API requests that act on behalf of other users in the same domain by replacing default in the API URL with the username of the user to impersonate (e.g. user@yourdomain.com). In order to utilize this feature, the request must be authorized as an administrative user of the same domain (e.g. admin@yourdomain.com). When impersonating a user, it does not matter if the target user is suspended or not. It is assumed that the Google Apps admin is capable of logging in, unsuspending the user, and making the request. Because of this, we circumvent that step for you, and allow Google Apps admins to make requests on behalf of suspended users (for example to copy a suspended user's resources).
An example of replacing default with the email address of the intended user is:
https://docs.google.com/feeds/user@yourdomain.com/...
An example request URL to impersonate user@yourdomain.com while authorized as admin@yourdomain.com using 3-Legged OAuth, AuthSub, or ClientLogin is:
https://docs.google.com/feeds/user@yourdomain.com/private/full/
An example request URL to impersonate user@yourdomain.com while authorized as admin@yourdomain.com using 2-Legged OAuth is:
https://docs.google.com/feeds/user@yourdomain.com/private/full?xoauth_requestor_id=admin@yourdomain.com
Although an @ symbol is shown in the above examples for clarity, URLs must be encoded prior to sending them to the API. With the above examples, that means replacing @ with %40. An example encoded URL is:
https://docs.google.com/feeds/user%40yourdomain.com/private/full?xoauth_requestor_id=admin%40yourdomain.com
Getting general information about a user's account
The metadata feed is a read-only feed that provides information about the feature set available to a given user account. For example, it can provide the necessary information for your client to customize its UI elements according to the feature set of the user.
To access a user's metadata, send an HTTP GET
to the following URI:
https://docs.google.com/feeds/metadata/<user-id>
Here, user-id
is the user's Google account email address (user@example.com,
user@gmail.com, etc.), or it is default if you want metadata for the currently
authorized user. This value must be URL encoded. Most commonly, you'll use
default:
https://docs.google.com/feeds/metadata/default
The response from the API includes a list of export formats supported by the API, quota information for the account, features available (and their request limits), maximum upload sizes, and additional roles supported by individual resource types. The following example is for a Google Apps for Business account:
Protocol
GET https://docs.google.com/feeds/metadata/default
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007" xmlns:gAcl="http://schemas.google.com/acl/2007" xmlns:gd="http://schemas.google.com/g/2005" gd:etag="W/"CkcMQH0zcSt7ImA9WhdQF0w."">
<id>https://docs.google.com/feeds/metadata/user%40example.com</id>
<updated>2011-08-18T23:28:01.389Z</updated>
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#metadata" label="metadata"/>
<title>Document List User Metadata</title>
<link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/metadata/user%40example.com"/>
<author>
<name>Some User</name>
<email>user@example.com</email>
</author>
<gd:quotaBytesTotal>1073741824</gd:quotaBytesTotal>
<gd:quotaBytesUsed>17936436</gd:quotaBytesUsed>
<docs:quotaBytesUsedInTrash>0</docs:quotaBytesUsedInTrash>
<docs:largestChangestamp value="101019"/>
<docs:importFormat source="application/vnd.openxmlformats-officedocument.presentationml.presentation" target="presentation"/>
<docs:importFormat source="application/vnd.ms-powerpoint" target="presentation"/>
<docs:importFormat source="text/tab-separated-values" target="spreadsheet"/>
<docs:importFormat source="image/gif" target="document"/>
<docs:importFormat source="application/x-msmetafile" target="drawing"/>
<docs:importFormat source="application/vnd.sun.xml.writer" target="document"/>
<docs:importFormat source="image/png" target="document"/>
<docs:importFormat source="application/vnd.ms-excel" target="spreadsheet"/>
<docs:importFormat source="image/bmp" target="document"/>
<docs:importFormat source="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" target="spreadsheet"/>
<docs:importFormat source="application/rtf" target="document"/>
<docs:importFormat source="application/msword" target="document"/>
<docs:importFormat source="application/vnd.oasis.opendocument.text" target="document"/>
<docs:importFormat source="text/plain" target="document"/>
<docs:importFormat source="text/csv" target="spreadsheet"/>
<docs:importFormat source="image/jpeg" target="document"/>
<docs:importFormat source="application/x-vnd.oasis.opendocument.spreadsheet" target="spreadsheet"/>
<docs:importFormat source="application/pdf" target="document"/>
<docs:importFormat source="application/vnd.openxmlformats-officedocument.wordprocessingml.document" target="document"/>
<docs:importFormat source="text/html" target="document"/>
<docs:exportFormat source="drawing" target="image/png"/>
<docs:exportFormat source="drawing" target="application/pdf"/>
<docs:exportFormat source="drawing" target="image/jpeg"/>
<docs:exportFormat source="document" target="application/msword"/>
<docs:exportFormat source="drawing" target="image/svg+xml"/>
<docs:exportFormat source="spreadsheet" target="application/pdf"/>
<docs:exportFormat source="document" target="application/rtf"/>
<docs:exportFormat source="spreadsheet" target="application/x-vnd.oasis.opendocument.spreadsheet"/>
<docs:exportFormat source="presentation" target="text/plain"/>
<docs:exportFormat source="document" target="application/pdf"/>
<docs:exportFormat source="document" target="text/plain"/>
<docs:exportFormat source="document" target="text/html"/>
<docs:exportFormat source="presentation" target="application/vnd.ms-powerpoint"/>
<docs:exportFormat source="spreadsheet" target="application/vnd.ms-excel"/>
<docs:exportFormat source="document" target="application/vnd.oasis.opendocument.text"/>
<docs:exportFormat source="document" target="text/rtf"/>
<docs:exportFormat source="presentation" target="application/pdf"/>
<docs:feature>
<docs:featureName>ocr</docs:featureName>
</docs:feature>
<docs:feature>
<docs:featureName>translation</docs:featureName>
<docs:featureRate>2.0</docs:featureRate>
</docs:feature>
<docs:feature>
<docs:featureName>upload_any</docs:featureName>
</docs:feature>
<docs:maxUploadSize kind="document">26214400</docs:maxUploadSize>
<docs:maxUploadSize kind="spreadsheet">10485760</docs:maxUploadSize>
<docs:maxUploadSize kind="presentation">10485760</docs:maxUploadSize>
<docs:maxUploadSize kind="drawing">2097152</docs:maxUploadSize>
<docs:maxUploadSize kind="pdf">10737418240</docs:maxUploadSize>
<docs:maxUploadSize kind="file">10737418240</docs:maxUploadSize>
<!-- The document resource type supports the additionalRoleSets given within. -->
<docs:additionalRoleInfo kind="document">
<!-- The reader role supports all additionalRoles given within. -->
<docs:additionalRoleSet primaryRole="reader">
<!-- Readers of text document resources are also able to comment on said
resources if the relevant additionalRole is provided in an ACL entry. -->
<gAcl:additionalRole value="commenter"/>
</docs:additionalRoleSet>
</docs:additionalRoleInfo>
</entry>
.NET
The following code fetches the feature set available to the currently authenticated user's account, and prints out the quota information and the list of supported import formats.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a MetadataQuery object to retrieve metadata.
MetadataQuery query = new MetadataQuery();
// Make a request to the API and get all information.
MetadataFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
throw new Exception("The metadata feed should always contain an entry");
}
// The metadata feed contains a single entry
MetadataEntry entry = (MetadataEntry)feed.Entries[0];
// Print quota information to the screen
Console.WriteLine(entry.QuotaBytesUsed);
Console.WriteLine(entry.QuotaBytesTotal);
// Iterate through all of the supported import formats
foreach (ConversionFormat format in entry.ImportFormats)
{
// Print the source and target formats
Console.WriteLine(format.Source + " -> " + format.Target);
}
}
}
}
The metadata feed has some optional parameters used by clients to determine the fastest way to reset a local cache. In some environments, like a mobile environment, both space and bandwidth may be limited. In these environments, a local cache consists of a small number of resources. This cache often represents the last X resources that were changed. Resources not tracked within the cache are found using some other mechanism, such as a search query.
One design consideration clients make in these environments involves the fact that the changes feed is FIFO, where as the main resources feed is LIFO. Thus, clients in these environments are often left with the question: "what is the fastest way to get the current state of the last X resources?" Is it to pull all changes from the changes feed, up to the latest change? Or, is it to pull X resources from the main resources feed? The former method is faster for small change sets. The latter method is faster for large changes sets, for instance if a client has not synced in a long time.
The metadata feed is used to answer this question. Given a changestamp and a limit, the metadata feed yields the number of changestamps since the given changestamp, up to the given limit.
Protocol
GET https://docs.google.com/feeds/metadata/default?remaining-changestamps-first=[changestamp-plus-one]&remaining-changestamps-limit=500
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:docs="http://schemas.google.com/docs/2007"
xmlns:gAcl="http://schemas.google.com/acl/2007"
xmlns:gd="http://schemas.google.com/g/2005"
gd:etag="W/"CkcMQH0zcSt7ImA9WhdQF0w."">
...
<docs:remainingChangestamps>344</docs:remainingChangestamps>
...
</entry>
.NET
The following code fetches the number of changestamps since changestamp 100, up to 500 changestamps.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a MetadataQuery object to retrieve metadata.
MetadataQuery query = new MetadataQuery();
// Set the RemainingChangestampsFirst parameter.
query.RemainingChangestampsFirst = 100;
// Set the RemainingChangestampsLimit parameter.
query.RemainingChangestampsLimit = 500;
// Make a request to the API and get all information.
MetadataFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
throw new Exception("The metadata feed should always contain an entry");
}
// The metadata feed contains a single entry
MetadataEntry entry = (MetadataEntry)feed.Entries[0];
// Print the number of remaining changestamps to the screen
Console.WriteLine(entry.RemainingChangestamps);
}
}
Providing the remaining-changestamps-first
parameter causes the metadata feed
to return the number of changestamps since the given changestamp, including the
given changestamp. Thus, to get the number of changestamps since a given
changestamp, clients must provide the last synced changestamp, plus one.
Using this mechanism of the metadata feed can increase the latency of a
metadata feed request. To minimize this latency, clients are required to
provide the remaining-changestamps-limit
parameter. This parameter gives an
upper bound to the value returned in docs:remainingChangestamps
. The previous
example indicates 344 changes since the given changestamp, because the given
remaining-changestamps-limit
is 500. The following example, assuming the same
environment and changestamp are provided, indicates only 10 changes since the
given changestamp, because of the lower remaining-changestamps-limit
value.
Technically, the following example yields a response more quickly than the
previous example.
GET https://docs.google.com/feeds/metadata/default?remaining-changestamps-first=[changestamp-plus-one]&remaining-changestamps-limit=10
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:docs="http://schemas.google.com/docs/2007"
xmlns:gAcl="http://schemas.google.com/acl/2007"
xmlns:gd="http://schemas.google.com/g/2005"
gd:etag="W/"CkcMQH0zcSt7ImA9WhdQF0w."">
...
<docs:remainingChangestamps>10</docs:remainingChangestamps>
...
</entry>
Once a client obtains the docs:remainingChangestamps
value, the client
decides whether to iterate over everything returned by the changes feed, or to
reset the local cache by pulling X resources from the main resources feed. If
there are a small number of changes, clients in a limited environment should
use the changes feed. If there are a large number of changes, said clients
should use the main resources feed. The definitions of small and large are up
to clients, as performance needs vary in each specific environment.
Detecting changes to resources
The changes feed is a read-only feed that provides information about all changes to all resources, including resources that have been shared with a user. The feed works by providing the current state of each resource, if and only if the resource has changed since the given changestamp.
For example, to detect changes to resources for synchronization with another data source, query the changes feed to detect the current state of resources that have changed.
The changes feed provides a more efficient way to detect changes to resources. Previously, developers polled all resources from a user's account repeatedly, which was inefficient and resource-intensive. The changes feed addresses these problems, and now developers must collect less data from the API to detect updates.
Using changestamps to identify changes
The concept of a changestamp is important to understand in order to use the changes feed. A changestamp is a unique, monotonically increasing integer representing each change to a user's documents list. Each entry in the feed has a changestamp value that uniquely and globally identifies a specific change to the relevant resource. Developers must store the value of the latest changestamp consumed by their application, and then query the API from that changestamp in the future. This process is repeated over time to detect changes. This ensures an application never receives the same change twice from the API. The exact URL structure for using changestamps is discussed below.
A given changestamp is only valid until the associated resource is changed
again. Once a resource changes, all previous changestamps for the resource
become invalid. This results in gaps between changestamps when the changes feed
is pulled. To detect if a specific resource has changed, GET
the self link of
the change. A 404 response to this request indicates that the resource has
since changed; a new changestamp is now associated with the resource and the
original changestamp is no longer valid. Otherwise, the change entry is
returned.
Retrieving changes for a user
Entries in the changes feed are ordered in ascending chronological order. That is, the oldest changes show up first. To collect all changes, follow all next links in the returned feed until there is no next link returned.
To access a user's changes feed, send an HTTP GET
to the following URI:
https://docs.google.com/feeds/<user-id>/private/changes
Here, user-id
is the user's Google account email address (user@example.com,
user@gmail.com, etc.), or it is default if you want changes for the currently
authorized user. This value must be URL encoded. Most commonly, you'll use
default:
https://docs.google.com/feeds/default/private/changes
The response from the API includes a GData feed of change entries. A change
entry is exactly like a normal resource entry from
/feeds/default/private/full
, except it also contains a docs:changestamp field
and possibly a docs:removed field.
Protocol
GET https://docs.google.com/feeds/default/private/changes
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
xmlns:docs="http://schemas.google.com/docs/2007" xmlns:gd="http://schemas.google.com/g/2005"
gd:etag="W/"DEEMQ3w8eyt7ImA9WhZUGUo."">
<id>https://docs.google.com/feeds/default/private/changes</id>
<updated>2011-06-13T14:51:22.273Z</updated>
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#change" label="change"/>
<title>Changed Documents - joe.smith@example.com</title>
<!-- Largest changestamp for the currently authorized user. -->
<!-- This value is also given in the Metadata feed. -->
<docs:largestChangestamp value="5635"/>
<!-- Follow this to get the next set of changes. -->
<!-- If this is not provided, there are no additional changes at the current time. -->
<link rel="next" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/changes?start-index=5636"/>
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/changes"/>
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/changes?start-index=5620"/>
<author>
<name>joe.smith</name>
<email>joe.smith@example.com</email>
</author>
<openSearch:totalResults>5635</openSearch:totalResults>
<openSearch:startIndex>5620</openSearch:startIndex>
<!-- This change represents a document being permanently deleted. -->
<entry gd:etag="W/"DUcMRHg5cCt7ImA9WhZUGUo."">
<id>https://docs.google.com/feeds/id/unknown%3A1H38bELcnXOWXL8eRZYAP4XvfR_EpEu_AJ1GZNJb9-N-4</id>
<updated>2011-06-13T14:58:05.628Z</updated>
<!-- Label representing that this is a change entry. -->
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#change" label="change"/>
<!-- docs:removed means this is change is a permanent deletion. Use this to detect deletes. -->
<!-- This field does NOT mean this resource was trashed. To identify trashed resources, use the gd:deleted tag. -->
<docs:removed/>
<!-- Title is unknown because this change is a deletion. -->
<title>Unknown</title>
<!-- Content link is empty because this change is a deletion. -->
<content/>
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/changes/5623"/>
<!-- Author is unknown because this change is a deletion. -->
<author>
<name>Unknown</name>
</author>
<!-- Resource type is unknown because this change is a deletion. -->
<gd:resourceId>unknown:1H38bELcnXOWXL8eRZYAP4XvfR_EpEu_AJ1GZNJb9-N-4</gd:resourceId>
<!-- Unique identifier for this change. Store this to query again in the future. -->
<docs:changestamp value="5623"/>
</entry>
<!-- This change represents a document being permanently deleted. -->
<entry gd:etag="W/"DUYEQH85cCt7ImA9WhZUGUo."">
<id>https://docs.google.com/feeds/id/unknown%3A17vRlM9HeTv_V03nxDXXnl9QvY-sL53e4tbiE0-5xD7e4</id>
<updated>2011-06-13T14:58:21.128Z</updated>
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#change" label="change"/>
<title>Unknown</title>
<content/>
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/changes/5630"/>
<author>
<name>Unknown</name>
</author>
<gd:resourceId>unknown:17vRlM9HeTv_V03nxDXXnl9QvY-sL53e4tbiE0-5xD7e4</gd:resourceId>
<docs:removed/>
<docs:changestamp value="5630"/>
</entry>
<!-- This change represents a document being created. -->
<entry gd:etag=""BlAIEQdOHCt7ImBr"">
<id>https://docs.google.com/feeds/id/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk</id>
<published>2011-06-13T15:05:37.544Z</published>
<updated>2011-06-13T15:05:38.108Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-13T15:05:38.456Z</app:edited>
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#document" label="document"/>
<category scheme="http://schemas.google.com/g/2005/labels"
term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
<title>Meeting Notes</title>
<content type="text/html"
src="https://docs.google.com/feeds/download/documents/export/Export?id=1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk"/>
<link rel="alternate" type="text/html"
href="https://docs.google.com/a/example.com/document/d/1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk/edit?hl=en_US"/>
<link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk"/>
<link rel="http://schemas.google.com/docs/2007/thumbnail" type="image/jpeg"
href="https://lh5.googleusercontent.com/u7NNUBIcKwb74epx_cb5ff_UoJDo5wm5M9zVRZq33qDfTnJyYo98uvP1CYI6hkEGFzEzG_QwqnLOabNkAg=s220"/>
<link rel="edit" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk"/>
<link rel="edit-media" type="text/html"
href="https://docs.google.com/feeds/default/media/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk"/>
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/changes/5635"/>
<author>
<name>joe.smith</name>
<email>joe.smith@example.com</email>
</author>
<gd:resourceId>document:1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk</gd:resourceId>
<gd:lastModifiedBy>
<name>joe.smith</name>
<email>joe.smith@example.com</email>
</gd:lastModifiedBy>
<gd:lastViewed>2011-06-13T15:05:38.108Z</gd:lastViewed>
<gd:quotaBytesUsed>0</gd:quotaBytesUsed>
<docs:writersCanInvite value="true"/>
<docs:changestamp value="5635"/>
<gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList"
href="https://docs.google.com/feeds/default/private/full/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk/acl"/>
<gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
href="https://docs.google.com/feeds/default/private/full/document%3A1DJ1Qrt_N41aX1nDxxo0QHs5XIM90zTT-seYG2FYxrRk/revisions"/>
</entry>
...
</feed>
.NET
The following code fetches a list of the currently authenticated user's changes, and prints out the title and changestamp of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a ChangesQuery object to retrieve changes.
ChangesQuery query = new ChangesQuery();
// Make a request to the API and get all changes.
ChangesFeed feed = service.Query(query);
// Iterate through all of the changes returned
foreach (ChangeEntry entry in feed.Entries)
{
// Print the title and changestamp of this document to the screen
Console.WriteLine(entry.Title.Text);
Console.WriteLine(entry.Changestamp);
}
}
}
}
After pulling the changes feed, the feed may or may not contain a next link. If the next link is present, it may be used to gather the next set of changes. If the next link is not present, the client application should store the changestamp of the last entry in the feed for future use. Changes in the feed are given in ascending chronological order, so the last change in the last page of the feed is the most recent change.
Retrieving all changes since a given changestamp
With the latest changestamp stored, the client application is prepared to query again for changes in the future. The next time the application queries for changes, it should use this URI:
https://docs.google.com/feeds/default/private/changes?start-index=[changestamp-plus-one]
Replace [changestamp-plus-one]
with the latest stored changestamp, plus one.
If the latest stored changestamp is 4351, then send 4352 here. This guarantees
that in the next request to the feed, an application does not also receive a
change received previously.
Protocol
GET https://docs.google.com/feeds/default/private/changes?start-index=4352
.NET
The following code fetches a list of the currently authenticated user's changes, starting from change 4352, and prints out the title and changestamp of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a ChangesQuery object to retrieve changes.
ChangesQuery query = new ChangesQuery();
// Set the StartIndex parameter.
query.StartIndex = 4352;
// Make a request to the API and get all changes.
ChangesFeed feed = service.Query(query);
// Iterate through all of the changes returned
foreach (ChangeEntry entry in feed.Entries)
{
// Print the title and changestamp of this document to the screen
Console.WriteLine(entry.Title.Text);
Console.WriteLine(entry.Changestamp);
}
}
}
}
Retrieving fewer changes per request
By default, the changes feed returns at most 100 changes. An application can
request up to 1000 changes per request. Also, if an application needs to
receive less data at once, for instance in a mobile setting, it can request
fewer changes. To change the number of changes returned, set the max-results
GET
parameter to a number less than or equal to 1000.
Protocol
GET https://docs.google.com/feeds/default/private/changes?start-index=[changestamp-plus-one]&max-results=900
.NET
The following code fetches a list of up to 900 of the currently authenticated user's changes, starting from change 4352, and prints out the title and changestamp of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a ChangesQuery object to retrieve changes.
ChangesQuery query = new ChangesQuery();
// Set the StartIndex parameter.
query.StartIndex = 4352;
// Set the NumberToRetrieve parameter.
query.NumberToRetrieve = 900;
// Make a request to the API and get all changes.
ChangesFeed feed = service.Query(query);
// Iterate through all of the changes returned
foreach (ChangeEntry entry in feed.Entries)
{
// Print the title and changestamp of this document to the screen
Console.WriteLine(entry.Title.Text);
Console.WriteLine(entry.Changestamp);
}
}
}
}
Showing the root collection as a parent in change entries
Just like the main Documents List API feed, the changes feed supports the
showroot
query parameter. This parameter causes the root collection to be shown
as a parent of any resource in the changes feed that has the root collection as
a parent. For more information, see Determining which resources are in the root
collection.
Retrieving ACL information for each change in the same request
The changes feed has a special parameter, expand-acl
, that expands the ACL of
each resource returned in the feed if set to true. As changes may show up in
the feed because of an ACL change, this can be particularly useful to
applications.
GET https://docs.google.com/feeds/default/private/changes?start-index=[changestamp-plus-one]&expand-acl=true
Protocol
https://docs.google.com/feeds/default/private/changes?start-index=[changestamp-plus-one]&expand-acl=true
.NET
The following code fetches a list of the currently authenticated user's changes, starting from change 4352 and with expanded ACL, and prints out the title and changestamp of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a ChangesQuery object to retrieve changes.
ChangesQuery query = new ChangesQuery();
// Set the StartIndex parameter.
query.StartIndex = 4352;
// Set the ExpandAcl parameter.
query.ExpandAcl = true;
// Make a request to the API and get all changes.
ChangesFeed feed = service.Query(query);
// Iterate through all of the changes returned
foreach (ChangeEntry entry in feed.Entries)
{
// Print the title and changestamp of this document to the screen
Console.WriteLine(entry.Title.Text);
Console.WriteLine(entry.Changestamp);
}
}
}
}
Changes representing a deletion
Changes that represent a deletion have a typed resource ID in which the
original type is replaced with unknown. For example, if there is a document
with a typed resource ID of document:1234abcd
, and this document is
permanently deleted, a change entry is created. The change entry has a resource
ID of unknown:1234abcd
. Note that the untyped resource ID does not change
after resource deletion. In the previous example, the untyped resource ID
remains 1234abcd
.
Getting profile information for users
Throughout the API, there are a number of places in which information about a specific user is returned. By default, this information is limited to an email address, and the first portion of the email address before the @.
Applications requiring additional information on these users can ask the API to
add public profile information for the users if it is available. If available,
the API adds a link to the primary public photo of the relevant user's Google
account. This is requested by appending include-profile-info=true
to any
request that may return user information, including the changes feed, resources
feed, ACL feed, etc.
Protocol
GET https://docs.google.com/feeds/default/private/full?include-profile-info=true
...
<entry>
...
<gd:lastModifiedBy>
<name>Joe Smith</name>
<uri>https://lh5.googleusercontent.com/-4IL6021224n0/AAAAAAI/AAREAAAA/rc12312LidA/photo.jpg</uri>
<email>joe.smith.test@gmail.com</email>
</gd:lastModifiedBy>
...
</entry>
...
.NET
The following code fetches a list of the currently authenticated user's documents, and prints out the email address of the user who last modified each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Set the IncludeProfileInfo parameter.
query.IncludeProfileInfo = true;
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the email address of the user who last modified the document.
Console.WriteLine(entry.LastModified.EMail);
}
}
}
}
Managing document and file metadata and content
The Documents List API has a primary feed for working with documents and files. This feed is exposed at the following URL.
https://docs.google.com/feeds/default/private/full
The following sections discuss how this URL, or some variation of it, can be used to manage resources.
Getting a list of documents and files
Protocol
You can get a feed containing a list of the currently authenticated user's
documents and files by sending an authorized GET
request to the following URL:
https://docs.google.com/feeds/default/private/full
The result is a feed that lists the user's documents and files; each entry in the feed represents a resource associated with the user.
The result will look something like this (comments have been added for clarity):
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
xmlns:docs="http://schemas.google.com/docs/2007" xmlns:batch="http://schemas.google.com/gdata/batch"
xmlns:gd="http://schemas.google.com/g/2005" gd:etag="W/"DUMFR3YyfCt7ImA9WxNTFU0."">
<!-- Unique identifier of this feed. Not unique between users. -->
<id>https://docs.google.com/feeds/default/private/full</id>
<!-- Date this feed was last updated. Do NOT use this, provided for Atom compliance only. -->
<updated>2009-08-17T11:10:16.894Z</updated>
<!-- Title of this feed result. -->
<title>Available Documents - john.smith.example@gmail.com</title>
<!-- Link at which a user could consume the same content given here, but in a web browser with a user interface. -->
<link rel="alternate" type="text/html" href="https://docs.google.com"/>
<!-- Link at which you can add documents or files using resumable upload. -->
<link rel="http://schemas.google.com/g/2005#resumable-create-media" type="application/atom+xml"
href="https://docs.google.com/feeds/upload/create-session/default/private/full"/>
<!-- Link at which you can fetch the next page of results from this feed. -->
<link rel="next" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full?start-key=EAEaFgoSCb2YGEPMAAACAG"/>
<!-- Link at which you can fetch this same feed. -->
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/"/>
<!-- Link at which you can fetch this same feed. -->
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full"/>
<!-- Deprecated. Use resumable-create-media instead. -->
<!-- Link at which you can POST new entries with metadata only to this feed. -->
<link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full"/>
<!-- Link at which you can send batch requests to this feed. -->
<link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/batch"/>
<!-- Information about the user who authorized this request. -->
<author>
<name>John Smith</name>
<email>john.smith.example@gmail.com</email>
</author>
<!-- NOT supported, provided for protocol compliance only. -->
<openSearch:startIndex>1</openSearch:startIndex>
<!-- The ETag here is used to identify the version of this entry. -->
<entry gd:etag="'EVJVTBICRit7ImBq'">
<!-- A unique, permanent identifier for this entry. -->
<id>https://docs.google.com/feeds/id/document%3A12345</id>
<!-- Title of this resource. -->
<title>2010 Income Tax Policy</title>
<!-- Description of this resource (currently visible in the preview pane in the UI). -->
<docs:description>Describes how to file income tax for 2010.</docs:description>
<!-- Resource ID of this document. -->
<gd:resourceId>document:12345</gd:resourceId>
<!-- Date this document was created (the "published" name of this element is mis-leading, but this is Atom standard). -->
<published>2009-07-22T19:02:57.616Z</published>
<!-- Information about the owner of this document (not necessarily the user authorizing this request). -->
<author>
<name>Jenna Dolsom</name>
<email>jenna.dolsom.example@gmail.com</email>
</author>
<!-- Date this entry was last updated (either by Google's systems, the API, or a user in a web browser). -->
<updated>2009-07-29T20:31:39.804Z</updated>
<!-- Date this document was last edited by a user in the document editor in a web browser. -->
<app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-31T17:21:26.497Z</app:edited>
<!-- Information about the user who last modified this entry (not necessarily the user authorizing this request). -->
<gd:lastModifiedBy>
<name>Aaron Jensen</name>
<email>aaron.jensen.example@gmail.com</email>
</gd:lastModifiedBy>
<!-- Date this document was last viewed in a web browser by any user. -->
<gd:lastViewed>2009-07-31T17:21:26.273Z</gd:lastViewed>
<!-- The "kind" of this entry. In this case, a word processing document. -->
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document" label="document"/>
<!-- This entry has been viewed by the user, so it has a "viewed" category. -->
<category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
<!-- Link at which you can download the actual document this entry describes. -->
<content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=12345"/>
<!-- This document is in one collection, detailed here. -->
<link rel="http://schemas.google.com/docs/2007#parent" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/folder%3A12345" title="ACollectionName"/>
<!-- Link at which you can open this document in a web browser. -->
<link rel="alternate" type="text/html" href="https://docs.google.com/Doc?docid=12345&hl=en"/>
<!-- Link at which you can fetch only this entry. -->
<link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/document%3A12345"/>
<!-- Link at which you can PUT updates to this entry. -->
<link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/document%3A12345"/>
<!-- Link at which you can PUT updates to this entry's content (deprecated, use resumable below). -->
<link rel="edit-media" type="text/html" href="https://docs.google.com/feeds/default/media/document%3A12345"/>
<!-- Link at which you can PUT resumable updates to this entry's content. -->
<link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345"/>
<!-- Link at which you can fetch a thumbnail of this resource. -->
<link rel="http://schemas.google.com/docs/2007/thumbnail" type="image/jpeg" href="https://lh3.googleusercontent.com/TQRs812345=s220"/>
<!-- Link at which you can create, retrieve, update, and delete ACL entries for this document. -->
<gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList"
href="https://docs.google.com/feeds/default/private/full/document%3A12345/acl"/>
<!-- Link at which you can create, retrieve, update, and delete revisions of this document. -->
<gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
href="https://docs.google.com/feeds/default/private/full/document%3A12345/revisions"/>
<!-- Number of bytes of the owner's quota this document uses. Native Google Docs currently use 0 bytes. -->
<gd:quotaBytesUsed>0</gd:quotaBytesUsed>
<!-- "true" if writers can invite other users to view and edit this document. -->
<docs:writersCanInvite value="true"/>
<!-- Given for files only. An MD5 checksum used to verify the contents of this file. -->
<!-- Some old files are being processed. Those files will not have this element yet. -->
<docs:md5Checksum>2b01142f7481c7b056c4b410d28f33cf</docs:md5Checksum>
<!-- Original filename of file at time of upload, if available. -->
<!-- Only available for resources of type file or pdf. -->
<!-- Shown here as example only. This element is not given for resources of type document. -->
<docs:filename>MyFile.pdf</docs:filename>
<!-- Current name of resource, with file extension from docs:filename appended, if available. -->
<!-- If the current name already has an extension, then the extension from docs:filename is not appended. -->
<!-- If docs:filename does not have an extension, then the current name is given unaltered. -->
<!-- Only available for resources of type file or pdf. -->
<!-- Shown here as example only. This element is not given for resources of type document. -->
<docs:suggestedFilename>TaxDocument.pdf</docs:suggestedFilename>
</entry>
<entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
<id>https://docs.google.com/feeds/id/pdf%3A12345</id>
<published>2009-04-09T18:23:09.035Z</published>
<updated>2009-04-09T18:23:09.035Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T22:16:02.388Z</app:edited>
<category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#starred" label="starred"/>
<category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
<category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#hidden" label="hidden"/>
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#pdf" label="pdf"/>
<title>PDF's Title</title>
<content type="application/pdf"
src="https://doc-04-20-docs.googleusercontent.com/docs/secure/m71240...U1?h=1630126&e=download&gd=true"/>
<link rel="alternate" type="text/html" href="https://docs.google.com/fileview?id=12345&hl=en"/>
<link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/pdf%3A12345"/>
<link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/pdf%3A12345"/>
<link rel="edit-media" type="application/pdf" href="https://docs.google.com/feeds/default/media/pdf%3A12345"/>
<link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
href="https://docs.google.com/feeds/upload/create-session/default/private/full/pdf%3A12345"/>
<author>
<name>user</name>
<email>user@gmail.com</email>
</author>
<gd:resourceId>pdf:12345</gd:resourceId>
<gd:lastModifiedBy>
<name>user</name>
<email>user@gmail.com</email>
</gd:lastModifiedBy>
<gd:lastViewed>2009-06-18T22:16:02.384Z</gd:lastViewed>
<gd:quotaBytesUsed>108538</gd:quotaBytesUsed>
<docs:writersCanInvite value="false"/>
<docs:md5Checksum>2b01142f7481c7b056c4b410d28f33cf</docs:md5Checksum>
<gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList"
href="https://docs.google.com/feeds/default/private/full/pdf%3A12345/acl"/>
<gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
href="https://docs.google.com/feeds/default/private/full/document%3A12345/revisions"/>
</entry>
...
</feed>
By default the API will return the first 100 documents and files in the user's
resource list. This saves bandwidth and improves performance. To request more
or less than 100 resources, use the max-results
GET
parameter with any
resources feed URL. Valid values for this parameter are integers from 1 to
1000, inclusive.
https://docs.google.com/feeds/default/private/full?max-results=1000
To include ACL information in this feed response, replace default
with
expandAcl
in the request URI.
https://docs.google.com/feeds/expandAcl/private/full
.NET
The following code fetches a list of the currently authenticated user's documents, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Parameter reference for resources collection URI
Parameter | Meaning | Notes |
---|---|---|
title |
Specifies the search terms for the title of a document. | This parameter used without title-exact will only
submit partial queries, not exact queries. |
title-exact |
Specifies whether the title query should be taken as
an exact string. |
Meaningless without title . Possible values are true and false .Note: Matches are case-insensitive. |
opened-min |
Lower bound on the last time a document was opened by the current user. | Use the RFC 3339 timestamp format. For example: opened-min=2005-08-09T09:57:00-08:00 |
opened-max |
Upper bound on the last time a document was opened by the current user. | Use the RFC 3339 timestamp format. For example: opened-max=2009-03-02T10:00:00 |
edited-min |
Lower bound on the last time a document was edited by the current user. This value corresponds to the <app:edited> value
in the Atom entry, which represents changes to the document's content or metadata. |
Use the RFC 3339 timestamp format. For example: edited-min=2005-08-09T09:57:00-08:00 |
edited-max |
Upper bound on the last time a document was edited by the user. This value corresponds to the <app:edited> value
in the Atom entry, which represents changes to the document's content or metadata. |
Use the RFC 3339 timestamp format. For example: edited-max=2009-08-09T09:57:00-08:00 |
owner |
Searches for documents with a specific owner. | Use the email address of the owner. For example: owner=user%40gmail.com |
writer |
Searches for documents which can be written to by specific users. | Use a single email address or a comma separated list of email addresses. For example: writer=user1%40gmail.com%2Cuser2%40example.com |
reader |
Searches for documents which can be read by specific users. | Use a single email address or a comma separated list of email addresses. For example: reader=user1%40gmail.com%2Cuser2%40example.com |
showfolders |
Specifies whether the query should return folders as well as documents. | Possible values are true and false . Default is false |
showdeleted |
Specifies whether the query should return documents which are in the trash as well as other documents. | Possible values are true and false . Default is false |
ocr |
Specifies whether to attempt OCR on a .jpg, .png, of .gif upload. | Possible values are true and false . Default is false . |
targetLanguage |
Specifies the language to translate a document into. | |
sourceLanguage |
Specifies the source language of the original document. | Optional when using the translation service. If not provided, Google will attempt to auto-detect the source language. |
delete |
Specifies whether or to permanently delete a document when trashing it. | Possible values are true and false . Default is false , meaning a document is moved to the trash. |
convert |
Specifies whether or not a document-type arbitrary file upload should be converted into a native Google Doc. | Optional when uploading a file. Possible values are true and false . Default is true . This parameter has no effect on PDFs or arbitrary file uploads. |
Getting all pages of documents and files
To retrieve resources beyond the first page, page through results by following the next link of a feed. In the example above, that link is:
<link rel="next" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full?start-key=EAEaFgoSCb2YGEPMAAACAG"/>
Getting a resource entry again
If you want to get a resource entry that you've retrieved before, you can improve efficiency by querying that specific entry and telling the server to send the entry only if it has changed since the last time you retrieved it.
To do this sort of conditional retrieval, send an HTTP GET
request that
includes an HTTP If-None-Match
header. In the header, specify the entry's ETag,
which you can find in the gd:etag
attribute. For example:
GET https://docs.google.com/feeds/default/private/full/resource_id
If-None-Match: "BxAaTxRZAyp7ImBq"
When the server receives this request, it checks to see whether the item that
you requested has the same ETag as the ETag you specified. If the ETags match,
then the item hasn't changed, and the server returns either an HTTP 304
Not
Modified status code or an HTTP 412
Precodition Failed status code. Either of
these status codes indicate that the item you already retrieved is up-to-date.
If the ETag doesn't match, then the item has been modified since the last time you requested it, and the server returns the item.
Searching for documents and files
You can search for documents or files using some of the standard Google Data API query parameters. Categories are used to restrict the type of resource (word processor, spreadsheet, presentation, collection, etc). returned. The full-text query string is used to search the content of all the documents.
Searching for resources by type
Retrieving all documents, files and collections
Collection entries are not returned in the feed by default. A list of all
resources, including collections, can be retrieved by using the showfolders
parameter on the list feed:
Protocol
GET https://docs.google.com/feeds/default/private/full?showfolders=true
.NET
The following code fetches a list of the currently authenticated user's documents and collections, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Set the showfolders parameter
query.ShowFolders = true;
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
For an example entry of the feed returned, look at the Getting a list of documents and files section.
Retrieving all text documents
A list of only word processor documents can be retrieved by using the document category as follows:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/document
.NET
The following code fetches a list of the currently authenticated user's text documents, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a TextDocumentQuery object to retrieve text documents.
TextDocumentQuery query = new TextDocumentQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving all spreadsheets
A list of only spreadsheets can be retrieved by using the spreadsheet category as follows:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/spreadsheet
.NET
The following code fetches a list of the currently authenticated user's spreadsheets, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a SpreadsheetQuery object to retrieve spreadsheets.
SpreadsheetQuery query = new SpreadsheetQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving all presentations
A list of only presentations can be retrieved by using the presentation category as follows:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/presentation
.NET
The following code fetches a list of the currently authenticated user's presentations, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a PresentationsQuery object to retrieve presentations.
PresentationsQuery query = new PresentationsQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving all drawings
A list of only drawings can be retrieved by using the drawing category as follows:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/drawing
.NET
The following code fetches a list of the currently authenticated user's drawings, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DrawingsQuery object to retrieve drawings.
DrawingsQuery query = new DrawingsQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving files by type
To return a list of files of MIME type application/msword, send a category query that includes the scheme + content type:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/{http://schemas.google.com/g/2005#kind}application/msword
GET https://docs.google.com/feeds/default/private/full/-/%7Bhttp%3A%2F%2Fschemas.google.com%2Fg%2F2005%23kind%7Dapplication%2Fmsword
.NET
The following code fetches a list of the currently authenticated user's application/msword files, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Add a QueryCategory corresponding to application/msword MIME type.
query.Categories.Add(new QueryCategory(
new AtomCategory("{http://schemas.google.com/g/2005#kind}application/msword")));
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving all starred presentations
You can combine more than one category. As an example, to retrieve a list of only starred presentations, use the presentation and starred categories together:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/presentation/starred
.NET
The following code fetches a list of the currently authenticated user's starred presentations, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a PresentationsQuery object to retrieve presentations.
PresentationsQuery query = new PresentationsQuery();
// Set the starred category
query.Starred = true;
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving all PDFs the user has viewed
As an example, to retrieve a list of viewed PDFs, use the viewed and pdf categories together:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/pdf/viewed
.NET
The following code fetches a list of the currently authenticated user's starred presentations, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a PDFsQuery object to retrieve PDFs.
PDFsQuery query = new PDFsQuery();
// Set the viewed category
query.Viewed = true;
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving a list of collections
A list of only collections can be retrieved by using the collection category as follows:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/folder
.NET
The following code fetches a list of the currently authenticated user's folders, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a FolderQuery object to retrieve folders.
FolderQuery query = new FolderQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving a list of trashed documents and files
A list of a user's trashed documents and files can be retrieved by using the trashed category as follows:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/trashed
Trashed resources are not included by default in query results. To include
them, use the showdeleted
parameter:
GET https://docs.google.com/feeds/default/private/full?showdeleted=true
.NET
The following code fetches a list of the currently authenticated user's trashed documents, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Set the trashed category
query.Trashed = true;
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Trashed resources are not included by default in query results. To include
them, use the showdeleted
parameter:
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Set the showdeleted parameter
query.ShowDeleted = true;
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving resources owned by a user
A list of PDFs owned by the requesting user:
Protocol
GET https://docs.google.com/feeds/default/private/full/-/pdf/mine
.NET
The following code fetches a list of the currently authenticated user's own PDFs, and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a PDFsQuery object to retrieve PDFs.
PDFsQuery query = new PDFsQuery();
// Set the mine category
query.Mine = true;
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Retrieving only shared resources
All resources that user1@gmail.com
and user2@gmail.com
are collaborating on:
Protocol
GET https://docs.google.com/feeds/default/private/full?writer=user1%40gmail.com%2Cuser2%gmail.com
.NET
The following code fetches a list of the resources user1@mail.com
and user2@gmail.com
are collaborating on, and prints out the
title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Set the writer parameter
query.Writer = "user1@gmail.com,user2@gmail.com";
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Searching for resources by title
You can search for resources matching an exact title or portion of a title by
using the title-exact
and title
query parameters, respectively. For
example, to search for resources matching the partial title "PR Handbook",
send:
Protocol
GET https://docs.google.com/feeds/default/private/full?title=%22PR+Handbook%22
To match a title exactly, add the title-exact
parameter:
GET https://docs.google.com/feeds/default/private/full?title=PR+Handbook&title-exact=true
.NET
The following code fetches a list of the resources matching the partial title "PR Handbook", and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Set the title parameter
query.Title = "PR Handbook";
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
To match a title exactly, add the title-exact
parameter:
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Set the title parameter
query.Title = "PR Handbook";
query.TitleExact = true;
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Searching for documents by full text query
You can search the content of documents by using the q
query parameter on the
feed. For example, to search a user's documents for the the words "dog" and
"cat", send the following authenticated GET
:
Protocol
GET https://docs.google.com/feeds/default/private/full?q=dog+cat
.NET
The following code searches the user's documents for the the words "dog" and "cat", and prints out the title of each of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Set the q parameter
query.Query = "dog+cat";
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in feed.Entries)
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
}
}
}
}
Full text query operators
The q
parameter supports a series of operators that allow searches to return
very specific results. These operators can be combined in order to narrow down
search results. An example is:
from:fluffy@catsndogs.com to:fido@catsndogs.com title:peace title:treaty after:2007-07-24 is:starred owner:fluffy@catsndogs.com
Name | Description | Example |
---|---|---|
Quotes | Matches contain the exact phrase in quotes. | "The quick brown fox jumps over the lazy dog." |
Conjunctions | Matches contain all of the given words. This is the default behavior. | cats AND dogs AND lizards |
Disjunctions | Matches contain one of the given words. | cats OR dogs OR lizards |
Exclusions | Matches do not contain the given words. | cats -dogs |
Title | Matches contain the given word in their title. | title:peace title:treaty |
Items shared by a user | Matches are shared by the given user. | from:fluffy@catsndogs.com |
Items shared with a user | Matches are shared with the given user. | to:fido@catsndogs.com |
Items owned by a user | Matches are owned by the given user. | owner:fluffy@catsndogs.com |
Starred items | Matches are starred. | is:starred |
Hidden items | Matches are hidden. | is:hidden |
Items of a certain type | Matches are of the given resource type. | type:document OR type:spreadsheet OR type:presentation OR type:video |
Edited date | Matches are edited before or after the given date. | before:2010-07-13 OR after:2007-07-24 |
Creating and uploading documents and files
Resources are uploaded to the API using a mechanism called resumable upload. This mechanism allows uploads to be broken up into individual parts, so that if uploading a single part fails, the part can be resent. Advantages of resumable upload include easier uploading of large files, better performance in bandwidth constrained environments, and easier user interface integrations (e.g. progress bars).
Below, the term metadata refers to the XML entry of a resource. The metadata of a resource is the series of attributes of the resource, including things like title or whether or not writers can invite others to the resource. It does not include resource content, which is the actual file content of a resource.
Clients creating and uploading resources are always in one of three scenarios.
- Creating a new, empty document or file with metadata only
-
- Clients in this scenario must send only a resource entry, but no resource content. Clients do this in order to create empty resources with just a title and/or other metadata.
- Uploading a new document or file with content only
-
- Clients in this scenario must send only resource content, but no resource entry. Clients do this to upload resources that do not need a title or other metadata.
- Uploading a new document or file with both metadata and content
- Clients in this scenario must send both a resource entry and resource content. Clients do this in order to, for example, upload a resource and give it a title, at the same time.
In all scenarios, clients must send an HTTP POST
request to the
resumable-create-media
link of the resources feed. To acquire this link,
clients query https://docs.google.com/feeds/default/private/full
. It is
recommended that clients not hard-code this link, in case the link changes. In
the following sections, this link is referred to as [resumable-create-media
link].
<link rel="http://schemas.google.com/g/2005#resumable-create-media"
type="application/atom+xml"
href="https://docs.google.com/feeds/upload/create-session/default/private/full"/>
Creating a new document or file with metadata only
Creating a new, empty resource with only metadata is the simplest way to create a resource, because it does not involve uploading any resource content. This scenario does not use most parts of the GData resumable upload protocol.
Protocol
The following example demonstrates a single HTTP request and the consequent HTTP response for creating an empty text document. The example can be applied to create other empty resources simply by changing the category of the provided resource entry.
POST [resumable-create-media link]
Content-Length: 359
Content-Type: application/atom+xml
X-Upload-Content-Length: 0
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
<!-- Replace the following line appropriately to create another type of resource. -->
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#document"/>
<title>Legal Contract</title>
</entry>
The API responds with the relevant response code and the new resource entry. Clients in this scenario need not do anything further. The resource has been created.
HTTP/1.1 201 Created
ETag: "HRcET05QHyt7ImBr"
...
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:docs="http://schemas.google.com/docs/2007"
xmlns:batch="http://schemas.google.com/gdata/batch"
xmlns:gd="http://schemas.google.com/g/2005"
gd:etag=""HRcET05QHyt7ImBr"">
<id>https://docs.google.com/feeds/id/file%3A0B9j-hQNOVsTFZTZkMmU0Y2UtNjNmYi00Y2RkLTkwODctMTg0NzdiZDNjZTg4</id>
<title>Legal Contract</title>
...
</entry>
.NET
The following code creates an empty text document with title "Legal Contract".
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentEntry object to be inserted.
DocumentEntry entry = new DocumentEntry();
// Set the document title
entry.Title.Text = "Legal Contract";
// Add the document category
entry.Categories.Add(DocumentEntry.DOCUMENT_CATEGORY);
// Make a request to the API and create the document.
DocumentEntry newEntry = service.Insert(
DocumentsListQuery.documentsBaseUri, entry);
}
}
}
Uploading a new document or file with content only
Creating a new resource with only content requires the use of the GData resumable upload protocol. When uploading a resource in this scenario, the resource will have a default title and metadata, depending on the MIME type of the content uploaded.
The following example demonstrates a full HTTP request and response sequence for uploading a 1 gigabyte PDF. The sequence consists of an initial request to create a resumable upload session, and then a large number of requests to upload the PDF in chunks of 512 kilobytes each. After all chunks are uploaded, the API issues a response indicating success or failure. The example can be applied to upload resources of any type.
POST [resumable-create-media link]
Content-Length: 0
X-Upload-Content-Type: application/pdf
X-Upload-Content-Length: 1073741824
HTTP/1.1 200 OK
Location: [next location]
...
PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 0-524287/1073741824
[bytes 0-524287]
HTTP/1.1 308 Resume Incomplete
Range: 0-524287
Location: [next location]
...
After receiving each chunk, the API issues an HTTP 308
response indicating
which bytes were successfully received. In the case that an HTTP 308
response
is not returned, clients must resend the failed chunk to the given [next
location]
. An example HTTP response requiring the previous chunk to be resent
is an HTTP 503
.
If an HTTP 308
is received and the byte range matches that which was last sent,
clients should proceed to send the next chunk.
PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 524288-1048575/1073741824
[bytes 524288-1048575]
HTTP/1.1 308 Resume Incomplete
Range: 524288-1048575
Location: [next location]
...
Repeat the previous step, sending the next consecutive 512 kilobytes, until there are no more bytes to send. After all bytes are uploaded, the server responds with a relevant status and the new resource entry.
HTTP/1.1 201 Created
ETag: "HRcET05QHyt7ImBr"
...
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:docs="http://schemas.google.com/docs/2007"
xmlns:batch="http://schemas.google.com/gdata/batch"
xmlns:gd="http://schemas.google.com/g/2005"
gd:etag=""HRcET05QHyt7ImBr"">
<id>https://docs.google.com/feeds/id/file%3A0B9j-hQNOVsTFZTZkMmU0Y2UtNjNmYi00Y2RkLTkwODctMTg0NzdiZDNjZTg4</id>
<title>Untitled document</title>
...
</entry>
Uploading a new document or file with both metadata and content
Creating a new resource with both metadata and content at once requires the use of the GData resumable upload protocol. When uploading a resource in this scenario, the resource will have the given title and metadata, as well as the given content.
The following example demonstrates a full HTTP request and response sequence for uploading a 1 gigabyte PDF titled "Legal Contract". The sequence consists of an initial request to create a resumable upload session with the given metadata, and then a large number of requests to upload the PDF in chunks of 512 kilobytes each. After all chunks are uploaded, the API issues a response indicating success or failure. The example can be applied to upload resources of any type with metadata.
Protocol
POST [resumable-create-media link]
Content-Length: 359
Content-Type: application/atom+xml
X-Upload-Content-Type: application/pdf
X-Upload-Content-Length: 1073741824
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
<title>Legal Contract</title>
</entry>
HTTP/1.1 200 OK
Location: [next location]
...
PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 0-524287/1073741824
[bytes 0-524287]
HTTP/1.1 308 Resume Incomplete
Range: 0-524287
Location: [next location]
...
After receiving each chunk, the API issues an HTTP 308
response indicating
which bytes were successfully received. In the case that an HTTP 308
response
is not returned, clients must resend the failed chunk to the given [next
location]. An example HTTP response requiring the previous chunk to be resent
is an HTTP 503
.
If an HTTP 308
is received and the byte range matches that which was last sent,
clients should proceed to send the next chunk.
PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 524288-1048575/1073741824
[bytes 524288-1048575]
HTTP/1.1 308 Resume Incomplete
Range: 524288-1048575
Location: [next location]
...
Repeat the previous step, sending the next consecutive 512 kilobytes, until there are no more bytes to send. After all bytes are uploaded, the server responds with a relevant status and the new resource entry.
HTTP/1.1 201 Created
ETag: "HRcET05QHyt7ImBr"
...
<?xml version="1.0" encoding="UTF-8"?>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:docs="http://schemas.google.com/docs/2007"
xmlns:batch="http://schemas.google.com/gdata/batch"
xmlns:gd="http://schemas.google.com/g/2005"
gd:etag=""HRcET05QHyt7ImBr"">
<id>https://docs.google.com/feeds/id/pdf%3A0B9j-hQNOVsTFZTZkMmU0Y2UtNjNmYi00Y2RkLTkwODctMTg0NzdiZDNjZTg4</id>
<title>Legal Contract</title>
...
</entry>
.NET
using System;
using Google.GData.Client;
using Google.GData.Client.ResumableUpload;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Instantiate an Authenticator object according to your authentication
// mechanism (e.g. OAuth2Authenticator).
// Authenticator authenticator = ...
// Instantiate a DocumentEntry object to be inserted.
DocumentEntry entry = new DocumentEntry();
// Set the document title
entry.Title.Text = "Legal Contract";
// Set the media source
entry.MediaSource = new MediaFileSource("c:\\contract.txt", "text/plain");
// Define the resumable upload link
Uri createUploadUrl = new Uri("https://docs.google.com/feeds/upload/create-session/default/private/full");
AtomLink link = new AtomLink(createUploadUrl.AbsoluteUri);
link.Rel = ResumableUploader.CreateMediaRelation;
entry.Links.Add(link);
// Set the service to be used to parse the returned entry
entry.Service = service;
// Instantiate the ResumableUploader component.
ResumableUploader uploader = new ResumableUploader();
// Set the handlers for the completion and progress events
uploader.AsyncOperationCompleted += new AsyncOperationCompletedEventHandler(OnDone);
uploader.AsyncOperationProgress += new AsyncOperationProgressEventHandler(OnProgress);
// Start the upload process
uploader.InsertAsync(authenticator, entry, new object());
}
static void OnDone(object sender, AsyncOperationCompletedEventArgs e) {
DocumentEntry entry = e.Entry as DocumentEntry;
}
static void OnProgress(object sender, AsyncOperationProgressEventArgs e) {
int percentage = e.ProgressPercentage;
}
}
}
Resuming an incomplete upload
If a request is terminated prior to receiving a resource entry from the API, or
if an HTTP 503
response is received, query the current status of the upload by
issuing an empty PUT
request to the last [next location] received from the API.
This allows clients to resume uploads even after a chunk fails to send
properly.
PUT [next location]
Content-Length: 0
Content-Range: bytes */1073741824
HTTP/1.1 308 Resume Incomplete
Range: 0-524287
Location: [next location]
...
After querying the status of the upload, resume the upload at the chunk after
the chunk described in the query response. In the above example, the byte range
0-524287
is the last chunk successfully sent. Thus, the client next sends the
byte range 524288-1048575
. At this point, the client continues the resumable
upload process described in previous sections.
PUT [next location]
Content-Length: 524288
Content-Type: application/pdf
Content-Range: bytes 524288-1048575/1073741824
[bytes 524288-1048575]
Creating or uploading text documents
To create a new, empty text document, follow the instructions in Creating a new
document or file with metadata only.
When doing so, use a category term of http://schemas.google.com/docs/2007#document
.
To upload and convert a text document, follow the instructions in Uploading a
new document or file with both metadata and
content.
When doing so, specify an HTTP X-Upload-Content-Type
of the MIME type of the
content being uploaded. Valid content types for conversion to Google Docs text
documents are specified by the metadata feed docs:importFormat
elements with
a target of document.
To upload a text document, but not convert it to a Google Doc (e.g. to upload
it as a file), follow the instructions in Uploading a new document or file
with both metadata and
content, but
also append ?convert=false
to the resumable-create-media
link.
Creating or uploading drawings
To create a new, empty drawing, follow the instructions in Creating a new
document or file with metadata
only. When doing so, use
a category term of http://schemas.google.com/docs/2007#drawing
.
To upload and convert a drawing, follow the instructions in Uploading a new
document or file with both metadata and
content.
When doing so, specify an HTTP X-Upload-Content-Type
of the MIME type of the
content being uploaded. Valid content types for conversion to Google Docs
drawings are specified by the metadata feed docs:importFormat
elements with a
target of drawing.
To upload a drawing, but not convert it to a Google Doc (e.g. to upload it as a
file), follow the instructions in Uploading a new document or file with both
metadata and
content, but
also append ?convert=false
to the resumable-create-media link.
Creating or uploading presentations
To create a new, empty presentation, follow the instructions in Creating a new
document or file with metadata
only. When doing so, use
a category term of http://schemas.google.com/docs/2007#presentation
.
To upload and convert a presentation, follow the instructions in Uploading a
new document or file with both metadata and
content.
When doing so, specify an HTTP X-Upload-Content-Type
of the MIME type of the
content being uploaded. Valid content types for conversion to Google Docs text
documents are specified by the metadata feed docs:importFormat
elements with
a target of presentation.
To upload a presentation, but not convert it to a Google Doc (e.g. to upload it
as a file), follow the instructions in Uploading a new document or file with
both metadata and
content, but
also append ?convert=false
to the resumable-create-media
link.
Creating or uploading spreadsheets
To create a new, empty spreadsheet, follow the instructions in Creating a new
document or file with metadata
only. When doing so, use
a category term of http://schemas.google.com/docs/2007#spreadsheet
.
To upload and convert a spreadsheet, follow the instructions in Uploading a
new document or file with both metadata and
content.
When doing so, specify an HTTP X-Upload-Content-Type
of the MIME type of the
content being uploaded. Valid content types for conversion to Google Docs text
documents are specified by the metadata feed docs:importFormat
elements with
a target of spreadsheet.
To upload a spreadsheet, but not convert it to a Google Doc (e.g. to upload it
as a file), follow the instructions in Uploading a new document or file with
both metadata and
content, but
also append ?convert=false
to the resumable-create-media
link.
Creating or uploading files
To create a new, empty file, follow the instructions in Uploading a new
document or file with both metadata and
content.
When doing so, send 0 bytes as the content body of the file. Also append
?convert=false
to the resumable-create-media link.
To upload a file, follow the instructions in Uploading a new document or file
with both metadata and
content, but
also append ?convert=false
to the resumable-create-media
link.
Uploading documents using Optical Character Recognition (OCR)
Optical Character Recognition gives applications the ability to convert high-resolution PDFs or images containing typewritten/printed text into editable text. As an example, applications could use this feature to upload scanned letters or old faxes to Google Docs. The API will attempt to extract the text from the PDFs or images, creating a new Google Doc for each image.
Limitations:
- Supported file formats:
application/pdf
,image/jpeg
,image/png
,image/gif
- Works best with high resolution images (at least 10 pixel character height)
- OCR is a computationally expensive operation and can take up to 30 seconds.
- Works only for latin character sets.
To perform OCR on a .pdf
, .jpg
, .png
, or .gif
file, include the ocr=true
parameter when uploading files:
POST [resumable-create-media link]?ocr=true
...
Hinting at languages
An additional parameter, ocr-language
, may be provided in order to hint at
which language to use when performing OCR. Even while providing this parameter,
if there is overwhelming evidence that a character or paragraph is of a certain
language, the hint will not be applied in that case.
Valid values for ocr-language
are ISO 639-1 codes. The following codes are
currently supported by the API.
bg, ca, chr, cs, da, de, el, en, es, fi, fil, fr, hi, hr, hu, id, it, iw, ja, ko, lt, lv, nl, no, pl, pt, ro, ru, sk, sl, sr, sv, th, tr, uk, vi, zh-Hans, zh-Hant
An example of specifying ocr-language
follows.
POST [resumable-create-media link]?ocr=true&ocr-language=zh-Hans
...
Uploading documents and automatically translating them
When uploading documents, clients can optionally translate the text of a
document into another language by specifying the targetLanguage=x
and
sourceLanguage=y
parameters. The API attempts to automatically detect the
sourceLanguage
if one is not provided. Generally, the automatic detection
works well, but if it fails, a relevant error is returned. Note also that not
all translation pairs are supported (e.g. Estonian to Chinese). If a client
attempts to use an unsupported pair, a relevant error message is returned.
This example translates the uploaded resource from English to German and stores the result as a Google Doc:
POST [resumable-create-media link]?sourceLanguage=en&targetLanguage=de
...
A full list of supported translation languages can be found by opening the "Tools > Translate Document" menu in the Google Docs web interface. Viable country codes can be found here.
Downloading documents and files
Once a client retrieves a resource's content
element, it can download the
file in a variety of formats. The content element is found in each resource
entry. An example follows.
<entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
...
<title>My PDF</title>
<content type="application/pdf"
src="https://doc-04-20-docs.googleusercontent.com/docs/secure/m71240U1?h=1630126&e=download&gd=true"/>
...
</entry>
Note that the content element gives the document or file's default export MIME type, as well as a full download URL for the document or file.
By default, documents are exported as HTML. Use the exportFormat
parameter
(described below) to download documents in alternate formats. Specifying a
different exportFormat for a document upon download is called converting the
document.
The default MIME type of a file upon download is the MIME type with which the file was uploaded. Files cannot be converted, and will have a different looking content URL than the ones described below.
Downloading text documents
The download URL for text documents looks something like this:
https://docs.google.com/feeds/download/documents/Export?docID=0AsJD12345&exportFormat=html&format=html
The document's download URL can be found in each entry under the content
element, along with the document's default MIME type.
If the download request was successful, an HTTP 200
is returned and the file is
served in the requested format.
If the download request failed, you will probably receive an HTTP 400 Could not
convert document
response, or an HTTP 500
response. Either of these errors
indicates an issue on the API's part in converting your document to the
specified format. If you received a 401 Unauthorized
response, then most likely
you did not get your OAuth/AuthSub token with the correct scopes (described
above).
Protocol
GET https://docs.google.com/feeds/download/documents/Export?docID=0AsJD12345&exportFormat=html&format=html
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Get the download url from the resource's content element
string downloadUrl = entry.Content.Src.Content;
// Add the exportFormat parameter
downloadUrl += "&exportFormat=html&format=html";
// Download the document as a stream
Stream stream = service.Query(new Uri(downloadUrl));
}
}
}
Valid download formats for text documents
When downloading text documents, the exportFormat
parameter controls the
format of the output. Valid values for this parameter appear below.
exportFormat Parameter Value | Format of the returned Document |
---|---|
docx |
Microsoft Word |
doc |
Microsoft Word |
html |
HTML Format |
jpeg |
Joint Photographic Experts Group Image Format (used for Google Drawings) |
odt |
Open Document Format |
pdf |
Portable Document Format |
png |
Portable Networks Graphic Image Format |
rtf |
Rich Text Format |
txt |
Text file |
zip |
ZIP archive. Contains the images (if any) used in the document, as well as a .html file containing the document's text. |
Downloading drawings
The download URL for drawings looks something like this:
https://docs.google.com/feeds/download/drawings/Export?docID=0AsJD12345&exportFormat=jpeg
The drawings's download URL can be found in each entry under the
If the download request is successful, an HTTP 200
is returned and the file is
served in the requested format.
Protocol
GET https://docs.google.com/feeds/download/drawings/Export?docID=0AsJD12345&exportFormat=jpeg
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Get the download url from the resource's content element
string downloadUrl = entry.Content.Src.Content;
// Add the exportFormat parameter
downloadUrl += "&exportFormat=jpeg";
// Download the document as a stream
Stream stream = service.Query(new Uri(downloadUrl));
}
}
}
Valid download formats for drawings
Drawing formats are also controlled via the exportFormat
parameter. Valid
values for this parameter appear below.
exportFormat Parameter Value | Format of the returned Document |
---|---|
jpeg |
Joint Photographic Experts Group Image Format |
pdf |
Portable Document Format |
png |
Portable Networks Graphic Image Format |
svg |
Scalable Vector Graphics Image Format |
Downloading presentations
The download URL for presentations looks something like this:
https://docs.google.com/feeds/download/presentations/Export?docID=0AsJD12345&exportFormat=png
The presentations's download URL can be found in each entry under the
If the download request is successful, an HTTP 200
is returned and the
presentation is served in the requested format.
Protocol
GET https://docs.google.com/feeds/download/presentations/Export?docID=0AsJD12345&exportFormat=png
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Get the download url from the resource's content element
string downloadUrl = entry.Content.Src.Content;
// Add the exportFormat parameter
downloadUrl += "&exportFormat=png";
// Download the document as a stream
Stream stream = service.Query(new Uri(downloadUrl));
}
}
}
Valid Formats for Presentations
Presentation formats are also controlled via the exportFormat
parameter.
Valid values for this parameter appear below.
exportFormat Parameter Value | Format of the returned Presentation |
---|---|
pdf |
Portable Document Format |
png |
Portable Networks Graphic Image Format |
ppt |
Powerpoint Format |
txt |
Text file |
Downloading spreadsheets
The download URL for spreadsheets looks something like this:
https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key=0AsJD12345&exportFormat=csv
The spreadsheet's download URL can be found in each entry under the
If the download request is successful, an HTTP 200
is returned and the
spreadsheet is served in the requested format.
If you received a 401 Unauthorized
response, then most likely you did not get
your OAuth/AuthSub token with the correct scopes (described above).
Protocol
GET https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key=0AsJD12345&exportFormat=csv
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Get the download url from the resource's content element
string downloadUrl = entry.Content.Src.Content;
// Add the exportFormat parameter
downloadUrl += "&exportFormat=csv";
// Download the document as a stream
Stream stream = service.Query(new Uri(downloadUrl));
}
}
}
Valid Formats for Spreadsheets
When downloading spreadsheets, the exportFormat
parameter controls the format
of the output. Valid values for this parameter appear below:
exportFormat Parameter Value | Format of the returned Spreadsheet |
---|---|
xlsx |
XLSX (Microsoft Excel) |
xls |
XLSX (Microsoft Excel) |
csv |
CSV (Comma Seperated Value). Only the first worksheet is returned in CSV by default. |
pdf |
PDF (Portable Document Format) |
ods |
ODS (Open Document Spreadsheet) |
tsv |
TSV (Tab Seperated Value). Only the first worksheet is returned in TSV by default. |
html |
HTML Format |
Downloading a single worksheet from a spreadsheet
When requesting a CSV, TSV, PDF, or HTML file you may specify an additional
(optional) parameter called gid
which indicates which worksheet you wish to
export (the index is 0 based, so gid 1 actually refers to the second worksheet
on a given spreadsheet). If left unspecified, the first worksheet is exported
for these formats. In the case of a PDF, the whole document is exported.
Here is an example download URL for a CSV representation of the second worksheet in a spreadsheet:
https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key=0AsJD12345&exportFormat=csv&gid=1
Protocol
GET https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key=0AsJD12345&exportFormat=csv&gid=1
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Get the download url from the resource's content element
string downloadUrl = entry.Content.Src.Content;
// Add the exportFormat parameter
downloadUrl += "&exportFormat=csv";
// Add the gid parameter
downloadUrl += "&gid=1";
// Download the document as a stream
Stream stream = service.Query(new Uri(downloadUrl));
}
}
}
Downloading files
Files cannot be downloaded in a format other than the one in which they were originally uploaded.
The download URL for files looks something like this:
https://doc-04-20-docs.googleusercontent.com/docs/secure/m7an0emtau/WJm12345/YzI2Y2ExYWVm?h=16655626&e=download&gd=true
The hostname used to serve files is different than that of documents for security reasons. It ensures that users cannot embed things like Javascript into the context of a page and access cookies created for other Google domains.
If the download request is successful, an HTTP 200
is returned and the file is
served in the requested format.
If you received a 401 Unauthorized
response, then most likely you did not get
your OAuth/AuthSub token with the correct scopes (described above).
Protocol
GET https://doc-04-20-docs.googleusercontent.com/docs/secure/m7an0emtau/WJm12345/YzI2Y2ExYWVm?h=16655626&e=download&gd=true
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Get the download url from the resource's content element
string downloadUrl = entry.Content.Src.Content;
// Download the file as a stream
Stream stream = service.Query(new Uri(downloadUrl));
}
}
}
In addition to downloading an entire file in a single request, the API supports downloading portions of a file as described in RFC 2616 using the HTTP Range header.
Assuming that an example file contains the bytes:
abcdefghijklmnopqrstuvwxyz
The following request to download a portion of the file yields only the intended bytes.
GET https://doc-0c-04-docs.googleusercontent.com/docs/securesc/lmdbchpbr0qbcdh0nq22dfe5mj5clv60/chsmg8c7b0gmmj9f3sn1hlahatdp9udr/1324168200000/05910256864069419770/05910256864069419770/0B3v1cNcx6HE-MTFlMTcxNGItMDI4NC00MTE3LTkwNDgtNTFmYzdjYjQ1MmNl?h=08181731109795882708&e=download&gd=true
Range: bytes=5-12
HTTP/1.1 206 Partial Content
status: 206
content-length: 8
x-google-cache-control: remote-fetch
content-disposition: attachment;filename="test.txt";filename*=UTF-8''test.txt
expires: Sun, 18 Dec 2011 00:37:45 GMT
server: HTTP Upload Server Built on Dec 13 2011 15:55:44 (1323820544)
content-range: bytes 5-12/37
via: HTTP/1.1 GWA
cache-control: private, max-age=0
date: Sun, 18 Dec 2011 00:37:45 GMT
content-type: text/plain
fghijklm
Updating/changing documents and files
To update an existing document or file, first retrieve the entry to update,
modify it as desired, and send a PUT
request to either the edit
link or the
edit-media link, depending on what is to be updated. Use this method only to
update metadata. This mechanism is not recommended for content updates, and may
be deprecated in the near future. For content updates, instead use the
resumable update mechanism, which is more scalable. If you are updating just a
resource's metadata, use the edit
link. If you are updating a resource's
content, use the edit-media link. If you are updating both metadata and
content, use the edit-media link. An example of these edit and edit-media links
in an entry follows:
<entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
...
<title>PDF's Title</title>
...
<link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/pdf%3A12345"/>
<link rel="edit-media" type="application/pdf" href="https://docs.google.com/feeds/default/media/pdf%3A12345"/>
...
</entry>
Use the self link for metadata changes on documents for which the user does not have edit access. An example would be starring a resource to which the user only has view access.
You can update any of the following:
- a document or file's metadata
- a document or file's content
- both metadata and content at once (using a multipart HTTP request)
The new document contents, which form part of the multipart HTTP request, must
have a Content-Type which is supported for conversion. For instance, when
updating a text document with new content, a Content-Type of either
application/msword or text/plain is supported, but application/vnd.ms-excel is
not. However, when updating a spreadsheet, application/vnd.ms-excel is
appropriate. Using a Content-Type that is unsuitable for the document type
being updated results in an HTTP 400 Bad Request
response.
This requirement to use a Content-Type that's compatible with the document type you're working with does not apply to files, as conversion is not supported for files.
For more information, see the complete list of accepted formats.
To make sure that your update doesn't overwrite another client's changes,
include the original entry's ETag value. You can do this by providing the ETag
value in an HTTP If-Match header, or by including the original entry's gd:etag
attribute in the updated entry. To determine the original resource's ETag
value, examine the
If you want to update the resource regardless of whether or not someone else has updated it since you retrieved it, then use If-Match: * and don't include the ETag.
Updating document or file metadata
Here is an example of updating a spreadsheet's metadata, but leaving its
content unchanged. The spreadsheet's name is changed to example spreadsheet,
and collaborators are allowed to share the document with users. Since the
request does not contain new spreadsheet content, the edit
link is used.
Protocol
PUT https://docs.google.com/feeds/default/private/full/spreadsheet%3A0Aj12345
Authorization: <your authorization header here>
Content-Length: 292
Content-Type: application/atom+xml
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007"
xmlns:gd="http://schemas.google.com/g/2005" gd:etag="BxAaTxRZAyp7ImBq">
<title>example spreadsheet</title>
<docs:writersCanInvite value="true" />
</entry>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Update the document's title
entry.Title.Text = "example spreadsheet";
// Allow collaborators to share the document with users
entry.WritersCanInvite = true;
// Make a request to the API and update the document.
entry.Update();
}
}
}
Updating document or file content with a simple PUT
Here is an example of changing the content of a document, but leaving its
metadata unchanged. The document's name is unchanged, but its contents is
replaced with the contents of test.doc. Since the request contains new document
content, the edit-media
link is used.
PUT https://docs.google.com/feeds/default/media/document:1234abcd
If-Match: <ETag or * here>
Authorization: <your authorization header here>
Content-Length: 70581
Content-Type: application/msword
Slug: test.doc
... doc contents here ...
Updating both metadata and content
Here is an example of updating both the document's metadata and its content at
the same time. The document's title is updated to example document
and its
contents are replaced with the contents of test.doc. Since the request contains
new document content, the edit-media
link is used.
Note that including the ETag for the metadata provides an implicit If-Match for the media content as well, because any update to the media content causes the metadata's ETag to change.
PUT https://docs.google.com/feeds/default/media/document:1234abcd
Authorization: <your authorization header here>
Content-Length: 73612
Content-Type: multipart/related; boundary="END_OF_PART"
Slug: test.doc
--END_OF_PART
Content-Type: application/atom+xml
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd="http://schemas.google.com/g/2005" gd:etag="BxAaTxRZAyp7ImBq">
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#document"/>
<title>example document</title>
</entry>
--END_OF_PART
Content-Type: application/msword
... doc contents here ...
--END_OF_PART
In all of these cases, a successful update returns an HTTP 200
OK status code
with an
Updating document or file content with the resumable protocol
Similar to initiating a resumable upload session, you can utilize the resumable
upload protocol to replace an existing document's content. To start a resumable
update request, send an HTTP PUT
to the entry link with rel
attribute
resumable-edit-media
. Each document or file entry that the currently
authorized user has permission to update will contain a resumable-edit-media
link.
<link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345"/>
Protocol
Here is the initial request:
PUT https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345
Authorization: <your authorization header here>
If-Match: <ETag or * here>
Content-Length: 1000
Content-Type: text/plain
X-Upload-Content-Length: 1000
X-Upload-Content-Type: text/plain
<empty body>
To update a resource's metadata and content at the same time, include Atom XML instead of an empty body. See the example in the Initiating a resumable upload request section.
When the server responds with the unique upload URI, send a PUT
with your
payload. Once the unique upload URI is fetched, the process for updating the
file's content is the same as uploading a file.
This is an example of updating an existing document's content all at once:
PUT <upload_uri>
Content-Length: 1000
Content-Range: 0-999/1000
<bytes 0-999>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Instantiate an Authenticator object according to your authentication
// mechanism (e.g. OAuth2Authenticator).
// Authenticator authenticator = ...
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Update the document's title
entry.Title.Text = "example spreadsheet";
// Set the media source
entry.MediaSource = new MediaFileSource("c:\\new_contract.txt", "text/plain");
// Instantiate the ResumableUploader component.
ResumableUploader uploader = new ResumableUploader();
// Set the handlers for the completion and progress events
uploader.AsyncOperationCompleted += new AsyncOperationCompletedEventHandler(OnDone);
uploader.AsyncOperationProgress += new AsyncOperationProgressEventHandler(OnProgress);
// Start the update process.
uploader.UpdateAsync(authenticator, entry, new object());
}
static void OnDone(object sender, AsyncOperationCompletedEventArgs e) {
DocumentEntry entry = e.Entry as DocumentEntry;
}
static void OnProgress(object sender, AsyncOperationProgressEventArgs e) {
int percentage = e.ProgressPercentage;
}
}
}
Forcing a new revision to be created when updating a resource
To force a new revision to be created when updating a resource, append
new-revision=true
to the PUT
URL.
PUT https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345?new-revision=true
Managing revisions of documents and files
Getting revisions of a document or file
Document and file revisions are available via the revisions feed. Every
document or file entry has a
<gd:feedLink rel="http://schemas.google.com/docs/2007/revisions"
href="https://docs.google.com/feeds/default/private/full/resource_id/revisions"/>
Protocol
To fetch the revision history for an item, send an HTTP GET
to the
rel
attribute of
http://schemas.google.com/docs/2007/revisions:
GET https://docs.google.com/feeds/default/private/full/resource_id/revisions
Authorization: <your authorization header here>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
xmlns:batch="http://schemas.google.com/gdata/batch" xmlns:gd="http://schemas.google.com/g/2005"
xmlns:docs="http://schemas.google.com/docs/2007"
gd:etag="W/"CE4HQX08cCt7ImA9WxNTFEU."">
<id>https://docs.google.com/feeds/default/private/full/resource_id/revisions</id>
<updated>2009-08-17T04:22:10.378Z</updated>
<title>Document Revisions</title>
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/resource_id/revisions"/>
<link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/batch"/>
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/resource_id/revisions"/>
<openSearch:totalResults>6</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<entry>
<id>https://docs.google.com/feeds/id/resource_id/revisions/0</id>
<updated>2009-08-17T04:22:10.440Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-06T03:25:07.798Z</app:edited>
<title>Revision 0</title>
<content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&revision=0"/>
<link rel="alternate" type="text/html"
href="https://docs.google.com/Doc?id=doc_id&revision=0"/>
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/0"/>
<author>
<name>user</name>
<email>user@gmail.com</email>
</author>
</entry>
<entry>
<id>https://docs.google.com/feeds/id/resource_id/revisions/1</id>
<updated>2009-08-17T04:22:10.440Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-06T03:25:07.799Z</app:edited>
<title>Revision 1</title>
<content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&revision=1"/>
<link rel="alternate" type="text/html"
href="https://docs.google.com/Doc?id=doc_id&revision=1"/>
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/1"/>
<author>
<name>user</name>
<email>user@gmail.com</email>
</author>
</entry>
<entry>
<id>https://docs.google.com/feeds/id/resource_id/revisions/2</id>
<updated>2009-08-17T04:22:10.440Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-14T07:11:34.197Z</app:edited>
<title>Revision 2</title>
<content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&revision=2"/>
<link rel="alternate" type="text/html"
href="https://docs.google.com/Doc?id=doc_id&revision=2"/>
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/2"/>
<link rel="http://schemas.google.com/docs/2007#publish" type="text/html"
href="https://docs.google.com/View?docid=doc_id&pageview=1&hgd=1"/>
<author>
<name>another_user</name>
<email>another_user@gmail.com</email>
</author>
<docs:publish value="true"/>
<docs:publishAuto value="true"/>
<docs:publishOutsideDomain value="false"/>
</entry>
</feed>
.NET
The following code fetches the list of revision for the first document in a feed. It first prints out the title of the document, and then prints a list of all revisions of that document.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
Console.WriteLine(entry.Title.Text);
// Instantiate a RevisionQuery object to retrieve revisions.
RevisionQuery revisionQuery = new RevisionQuery(entry.RevisionDocument);
// Make a request to the API and get all revisions.
RevisionFeed revisions = service.Query(revisionQuery);
// Iterate through all of the revisions returned
foreach (RevisionEntry revision in revisions.Entries)
{
// Print the title of this revision to the screen
Console.WriteLine(revision.Title.Text);
Console.WriteLine(revision.Publish);
foreach (AtomPerson author in revision.Authors)
{
// Print the name of each revision's author to the screen
Console.WriteLine(author.Name);
}
}
}
}
}
Properties of a revision entry:
- The
<updated>
field is the timestamp a revision was created. - The
<author>
field is the creator of that revision. - A
<docs:publish>
field is present and set to true if the revision is published. The entry has a link withrel
set to "http://schemas.google.com/docs/2007#publish" pointing to the published document on the web. A<docs:publishAuto>
field is present if the revision is published. Its value is true if the "Automatically re-publish when changes are made" checkbox is selected in the Google Docs UI. - A
<docs:publishOutsideDomain>
field is present if the revision is published and the document is in a Google Apps domain. Its value is true (the default) if the document is published outside of the domain.
Downloading individual revisions
The <content>
field's src
attribute can be used to Export a particular revision
in the API's supported exportFormats:
<content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&revision=2"/>
The following example downloads 'Revision 2' (from the XML above) as a .txt file:
Protocol
GET https://docs.google.com/feeds/download/documents/Export?docId=doc_id&revision=2&exportFormat=txt
Authorization: <your authorization header here>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Get the download url from the resource's content element
string downloadUrl = entry.Content.Src.Content;
// Add the exportFormat parameter
downloadUrl += "&exportFormat=txt";
// Add the revision parameter
downloadUrl += "&revision=2";
// Download the document as a stream
Stream stream = service.Query(new Uri(downloadUrl));
}
}
}
Deleting file revisions
At this time, only file revisions may be deleted with the API. The ability to delete document revisions may be added in a later release.
To delete file revisions, simply send a DELETE
request to the edit
link of a
revision entry.
DELETE https://docs.google.com/feeds/default/private/full/resource_id/revisions/revision_id
An HTTP 200
response indicates success in deleting the revision.
Protocol
DELETE https://docs.google.com/feeds/default/private/full/resource_id/revisions/revision_id
Authorization: <your authorization header here>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Instantiate a RevisionQuery object to retrieve revisions.
RevisionQuery revisionQuery = new RevisionQuery(entry.RevisionDocument);
// Make a request to the API and get all revisions.
RevisionFeed revisions = service.Query(revisionQuery);
if (revisions.Entries.Count == 0)
{
// TODO: There were no revisions, act accordingly.
}
// TODO: Choose a revision based on your app's needs.
RevisionEntry revision = (RevisionEntry)revisions.Entries[0];
// Make a request to the API and delete the revision.
revision.Delete();
}
}
}
Publishing documents by publishing a single revision
The API supports the following modifications to a document's published settings:
- Publish/unpublish a document
- Publish a document at a different revision
- Change whether document changes are auto-republished
- Change whether documents are published outside of a Google Apps domain
To change the published settings on a document, send an HTTP PUT
to the edit
link on the revision entry for the revision you want to change. The request
body should contain the modified revision entry.
This example publishes revision 1 from the revision feed example above by adding the necessary published elements to the entry:
Protocol
PUT https://docs.google.com/feeds/default/private/full/resource_id/revisions/revision_number
Authorization: <your authorization header here>
Content-Length: 722
Content-Type: application/atom+xml
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gd='http://schemas.google.com/g/2005'
xmlns:docs="http://schemas.google.com/docs/2007" gd:etag="W/"DkIBR3st7ImA9WxNbF0o."">
<id>https://docs.google.com/feeds/id/resource_id/revisions/1</id>
<updated>2009-08-17T04:22:10.440Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2009-08-06T03:25:07.799Z</app:edited>
<title>Revision 1</title>
<content type="text/html" src="https://docs.google.com/feeds/download/documents/Export?docId=doc_id&revision=1"/>
<link rel="alternate" type="text/html"
href="https://docs.google.com/Doc?id=doc_id&revision=1"/>
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/resource_id/revisions/1"/>
<author>
<name>user</name>
<email>user@gmail.com</email>
</author>
<docs:publish value="true"/>
<docs:publishAuto value="false"/>
</entry>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Instantiate a RevisionQuery object to retrieve revisions.
RevisionQuery revisionQuery = new RevisionQuery(entry.RevisionDocument);
// Make a request to the API and get all revisions.
RevisionFeed revisions = service.Query(revisionQuery);
if (revisions.Entries.Count == 0)
{
// TODO: There were no revisions, act accordingly.
}
// TODO: Choose a revision based on your app's needs.
RevisionEntry revision = (RevisionEntry)revisions.Entries[0];
// Change the publishing settings.
revision.Publish = true;
revision.PublishAuto = true;
// Make a request to the API and update the revision.
revision.Update();
}
}
}
Note that
Toggling properties of documents and files
Resources optionally have a number of category elements indicating that the given resource belongs to some category. Examples are the viewed, starred, and hidden categories. Boolean resource properties such as these may be toggled on or off.
To toggle a given property on when creating or updating a resource, provide the full category element representing the relevant category.
<entry>
...
<!-- Set the resource as viewed. -->
<category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
...
</entry>
To toggle a given property off when creating or updating a resource, provide the category element, but set the label attribute to empty.
<entry>
...
<!-- Unstar the resource. -->
<category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#starred" label=""/>
...
</entry>
Copying documents
To duplicate a document in a user's Google Docs list, send an HTTP POST
to the
URI https://docs.google.com/feeds/default/private/full. The POST
body must be
an entry with an id
element set to one of the following:
- the
self
link of theentry
from which you are copying - the resource ID of the source
entry
The following example shows how to duplicate a document in Google Docs:
Protocol
This example uses the self
link of the source entry
:
POST https://docs.google.com/feeds/default/private/full
Authorization: <your authorization header here>
Content-Length: 292
Content-Type: application/atom+xml
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>https://docs.google.com/feeds/default/private/full/document:12345</id>
<title>My Copy</title>
</entry>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry source = (DocumentEntry)feed.Entries[0];
// Instantiate a DocumentEntry object to be inserted.
DocumentEntry entry = new DocumentEntry();
// Set the document title
entry.Title.Text = "Copy of Legal Contract";
// Copy the resource ID of the source document
entry.Id = source.Id;
// Make a request to the API and copy the document.
entry = service.Insert(DocumentsListQuery.documentsBaseUri, entry);
}
}
}
Trashing documents and files
Trashing a document or file moves the resource to the user's trash collection.
First, retrieve the entry for the document or file, then send a DELETE
request to the entry's edit URL. This is the same URL used to update the
document or file.
Protocol
DELETE https://docs.google.com/feeds/default/private/full/resource_id
If-Match: <ETag or * here>
Authorization: <your authorization header here>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Make a request to the API and trash the document.
service.Delete(entry);
}
}
}
If the resource is trashed successfully, the server responds with an HTTP 200
OK.
To protect against deleting a document or file that has been changed by another
client since the entry was last retrieved, include an HTTP If-Match
header
that contains the original entry's ETag value. Determine the original entry's
ETag value by examining the entry
element's gd:etag
attribute.
To delete the document or file regardless of whether another user has updated
it since the entry was last retrieved, use If-Match: *
and don't include the
ETag. It's not necessary to retrieve the ETag entry attribute before deleting
the document in this case.
Deleting documents and files
Deleting a document or file permanently removes the resource from the user's
documents list. The process for deleting a document or file is similar to
trashing, but you must include the delete=true
parameter.
Protocol
DELETE https://docs.google.com/feeds/default/private/full/resource_id?delete=true
If-Match: <ETag or * here>
Authorization: <your authorization header here>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Make a request to the API and delete the document.
service.Delete(entry, true);
}
}
}
If the resource is deleted successfully, the server responds with an HTTP 200
OK.
Batching resource operations into a single request
The Google Documents List API supports GData batch processing. This allows clients to combine multiple operations into a single request that without batch processing are more than one request. For instance, a client can fetch resource A, create an empty resource B, update the metadata of resource C, and delete resource D, all in a single request. There are a number of advantages to performing batch operations, one of which is bandwidth conservation in bandwidth constrained environments.
To perform batch processing of operations, POST
a resource feed to the batch
link given with each Documents List API resource feed request.
<link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/batch"/>
Each resource in the POST
ed feed must contain a batch:operation
element,
describing which operation to perform on the resource. Valid operations are
query, insert, update, and delete.
When creating new, empty resources in a batch operation, assign the operations
a batch:id
so that clients can identify the new resource in the batch
response.
The following is an example of a batch request and response that retrieves, creates, updates, and deletes four resources.
POST https://docs.google.com/feeds/default/private/full/batch
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:docs="http://schemas.google.com/docs/2007"
xmlns:batch="http://schemas.google.com/gdata/batch"
xmlns:gd="http://schemas.google.com/g/2005">
<entry>
<id>https://docs.google.com/feeds/id/file:1234abcd</id>
<batch:operation type="query"/>
</entry>
<entry>
<!-- Since a new resource has no ID, specify a batch operation ID in
order to identify this resource in the response. -->
<batch:id>1</batch:id>
<batch:operation type="insert"/>
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#document"
label="document"/>
<title>New Text Document</title>
</entry>
<entry gd:etag=""SJDnxi3203sns"">
<id>https://docs.google.com/feeds/id/drawing:5678efgh</id>
<batch:operation type="update"/>
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#drawing"
label="drawing"/>
<title>Updating Drawing</title>
</entry>
<entry gd:etag=""ghxcoi309sjhdDHD"">
<id>https://docs.google.com/feeds/id/pdf:9012ijkl</id>
<batch:operation type="delete"/>
</entry>
</feed>
The corresponding response to the above request follows, containing one entry for each operation in the request.
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
xmlns:docs="http://schemas.google.com/docs/2007"
xmlns:batch="http://schemas.google.com/gdata/batch"
xmlns:gd="http://schemas.google.com/g/2005">
<id>https://docs.google.com/feeds/id/batch/1316013557203</id>
<updated>2011-09-14T15:19:17.683Z</updated>
<title>Batch Feed</title>
<entry gd:etag=""Gk4MUA9MGSt7ImBr"">
<id>https://docs.google.com/feeds/id/file:1234abcd</id>
<published>2011-09-09T15:05:02.608Z</published>
<updated>2011-09-10T22:55:20.141Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-12T16:46:09.251Z</app:edited>
<category scheme="http://schemas.google.com/g/2005/labels"
term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#file" label="file"/>
<title>Photo of Doug falling in the pool</title>
...
<batch:status code="200" reason="Success"/>
<batch:operation type="query"/>
...
</entry>
<entry gd:etag=""Gk0ESAkKRCt7ImBr"">
<id>https://docs.google.com/feeds/id/document:3456mnop</id>
<published>2011-09-14T15:19:17.840Z</published>
<updated>2011-09-14T15:19:19.053Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-14T15:19:19.059Z</app:edited>
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#document"
label="document"/>
<category scheme="http://schemas.google.com/g/2005/labels"
term="http://schemas.google.com/g/2005/labels#viewed"
label="viewed"/>
<title>New Text Document</title>
...
<batch:id>1</batch:id>
<batch:status code="201" reason="Created"/>
<batch:operation type="insert"/>
...
</entry>
<entry gd:etag=""Gk0EUhxCASt7ImBr"">
<id>https://docs.google.com/feeds/id/drawing:5678efgh</id>
<published>2011-09-01T16:11:17.781Z</published>
<updated>2011-09-14T15:26:42.209Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-14T15:26:42.211Z</app:edited>
<category scheme="http://schemas.google.com/g/2005/labels"
term="http://schemas.google.com/g/2005/labels#viewed"
label="viewed"/>
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#drawing"
label="drawing"/>
<title>Updating Drawing</title>
...
<batch:status code="200" reason="Success"/>
<batch:operation type="update"/>
...
</entry>
<entry>
<id>https://docs.google.com/feeds/id/pdf:9012ijkl</id>
<updated>2011-09-14T15:26:42.765Z</updated>
<title>Deleted</title>
<content>Deleted</content>
<batch:status code="200" reason="Success"/>
<batch:operation type="delete"/>
</entry>
</feed>
Managing collections and their contents
Before reading this section, make sure you read the Terminology used in this guide.
The API allows you to manage collections in the Google Docs user interface. With the API, you can create, retrieve, update, trash, and delete collections. Other operations, like "move", are provided via create, retrieve, update, and delete operations on a collection's content feed.
How Google Docs organizes and manages collections
Collections allow a resource to maintain a "many to many" relationship with each other. In other words, collections allow resources to exist in multiple collections at the same time. Collections are conceptually similar to "labels" in Gmail, except that collections also allow for hierarchy. This is possible because a collection is also a resource, and therefore can also exist within other collections, allowing this hierarchy to form in a composite pattern.
In general, resources link directly to the collection that contains them. In the API, every resource has a set of parent links, and each link represents a link to a collection that contains that given resource. A parent link cannot occur more than once in a resource's set of parent links, and the set of parent links is always of size 0 or greater.
If a resource does not link to a named collection that's visible in the Google Docs user interface, it is usually in the "root" collection by default.
There are two cases where a resource may not be linked to a visible parent collection and will not appear in the "root" collection. In both of these cases, the resource still appears in the user's feed.
The first case is when a resource is shared with a user but not placed in a collection. In this case, the resource appears in the user's feed, and does not appear in any collection, including the "root" collection.
The second case is when a resource is shared with a Google Apps domain, not placed in a collection, and opened up for viewing by the user. In this case the resource is in no collections, including the root, but appears in the user's feed.
The "root" collection itself only exists in the API and is not directly represented in the user interface. Instead, all of a user's resources fall under the visual labels "All items," "My collections," and "Collections shared with me."
The overall hierarchy of a given account is complex and can't be visualized like a "tree" despite having a root collection. Instead, think of it more like an interconnected net attached to a single root point. The root collection contains other collections, documents, and files, but beyond this, there isn't necessarily a linear hierarchy. Documents and files within "root" may also exist in other collection, creating a complex web of relationships between resources.
Getting a list of collections
To get a list of all collections for a user, use the collection search query.
To include collections in result sets that would normally just include
documents and files, add showfolders=true
to the URL. Collections are by
default not included in API responses that do not contain exclusively
collections (e.g. a request to /feeds/default/private/full will not include
collection entries by default). Thus, to search for collections by title, see
the section Searching for documents and files,
and just add showfolders=true
to any of the search examples given there.
Determining which resources are in the root collection
To determine which resources are in the root collection, attach showroot=true
to any HTTP request to the API that returns resources.
Protocol
GET https://docs.google.com/feeds/default/private/full?showroot=true
Authorization: <your authorization header here>
This will cause the API to return a feed of resources that looks something like:
<entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
...
<title>PDF's Title</title>
...
</entry>
<entry xmlns:gd="http://schemas.google.com/g/2005" gd:etag="'HhJSFgpeRyt7ImBq'">
...
<title>PDF's Title</title>
...
<link rel="http://schemas.google.com/docs/2007#parent"
type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/folder%3Aroot"
title="My items"/>
...
</entry>
...
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Set the ShowRoot parameter.
query.ShowRoot = true;
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
}
}
}
Note how the second resource in the above example actually belongs to the root
collection, while the first resource does not. My items is not necessarily
always the name of the root collection. Detect the root collection instead by
using the resource ID folder:root
.
The showroot
parameter does not cause the root collection to show up as a
separate entry in feeds of collections. It only causes the root collection to
be shown as a parent of relevant resources. For instance, if you made the
following request, you would NOT see the root collection as an entry. The root
collection would be included, as appropriate, in the parent list of the
resulting collection entries.
https://docs.google.com/feeds/default/private/full/-/folder?showroot=true
When getting entries back from API feeds, you will never find a resource entry with a resource ID of folder:root because the root collection does not have its own entry. You cannot update, delete, move, or otherwise change the root collection.
The resource ID of the root collection will always be folder:root
, and its
parent link href in resource entries will always be:
https://docs.google.com/feeds/default/private/full/folder%3Aroot
When writing code that interfaces with the API and uses the root collection, it is recommended you declare a constant for the above link, and use that to test for presence of a root collection parent link.
If you're looking for things that are only in the root collection, an easier way to find them is to make the following query:
https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents
Because the root collection is almost like any other collection, it has a contents feed, which is described in more detail below.
A list of collections in the root collection can be queried using the root collection's collection category feed:
https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents/-/folder
Similarly, a list of spreadsheets in the root collection can be queried using the root collection's spreadsheet category feed:
https://docs.google.com/feeds/default/private/full/folder%3Aroot/contents/-/spreadsheet
Getting the metadata and contents of an individual collection
To retrieve a list of items in a particular collection, send an HTTP GET
to the
collection's feed URL:
https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/contents
By default, collection entries will also be returned within the collections
feed (e.g. you don't have to include the showfolders=true
parameter).
Protocol
GET https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/contents
Authorization: <your authorization header here>
The feed of a collection's contents will look something like this:
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/"
xmlns:docs="http://schemas.google.com/docs/2007" xmlns:batch="http://schemas.google.com/gdata/batch" xmlns:gd="http://schemas.google.com/g/2005"
gd:etag="W/"DkQDQH4_eSt7ImA9WxNTEkw."">
<!-- Unique identifier of this feed. Not unique between users. -->
<id>https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents</id>
<!-- Date this collection's contents were last updated. Do NOT use this, provided for Atom compliance only. -->
<updated>2009-08-14T01:46:11.041Z</updated>
<!-- Title of this feed result. -->
<title>Available Documents - john.smith.example@gmail.com</title>
<!-- Link at which a user could see this collection's contents in a web browser. -->
<link rel="alternate" type="text/html" href="https://docs.google.com/#folders/folder.0.0B9kQ4KIBsdfYzNmNiMjI4N"/>
<!-- Link at which you can fetch this same feed. -->
<link rel="self" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents"/>
<!-- Link at which you can fetch this same feed. -->
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents"/>
<!-- Link at which you can POST new entries with metadata only to this feed (e.g. to add items to this collection). -->
<link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents"/>
<!-- Link at which you can send batch requests to this feed. NOT supported by Documents List API, provided for GData compliance. -->
<link rel="http://schemas.google.com/g/2005#batch" type="application/atom+xml"
href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents/batch"/>
<!-- Information about the owner of this collection. -->
<author>
<name>John Smith</name>
<email>john.smith.example@gmail.com</email>
</author>
<!-- NOT supported, provided for protocol compliance only. -->
<openSearch:startIndex>1</openSearch:startIndex>
<entry gd:etag=""BEFd33dgfImBr"">
<id>https://docs.google.com/feeds/id/document%3A1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk</id>
<published>2011-04-13T10:44:28.877Z</published>
<updated>2011-04-13T10:44:29.253Z</updated>
<app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-13T10:44:30.113Z</app:edited>
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/docs/2007#document" label="document"/>
<category scheme="http://schemas.google.com/g/2005/labels" term="http://schemas.google.com/g/2005/labels#viewed" label="viewed"/>
<title>My document</title>
<content type="text/html" src="https://docs.google.com/feeds/download/documents/export/Export?id=1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk"/>
<link rel="http://schemas.google.com/docs/2007#parent" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N" title="Example Folder"/>
<link rel="alternate" type="text/html" href="https://docs.google.com/a/google.com/document/d/1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk/edit?hl=en"/>
<link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml" href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk"/>
<link rel="http://schemas.google.com/docs/2007/thumbnail" type="image/jpeg" href="https://lh6.googleusercontent.com/q78pafbgaRCrpzxcbdfgw437h4o-Jqv1s5MS7vwaIBfWxMSXIEg9-geu2g73EvvV5oiTlunjpnf9H0OQ=s220"/>
<link rel="self" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk"/>
<link rel="edit" type="application/atom+xml" href="https://docs.google.com/feeds/default/private/full/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/contents/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk"/>
<link rel="edit-media" type="text/html" href="https://docs.google.com/feeds/default/contentmedia/folder%3A0B9kQ4KIBsdfYzNmNiMjI4N/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk"/>
<author>
<name>user</name>
<email>user@gmail.com</email>
</author>
<gd:resourceId>document:1j8yrZUCg234gdsgaxcz7tyBDHsy_vZeUfXfZNAffHatXXqk</gd:resourceId>
<gd:lastModifiedBy>
<name>user</name>
<email>user@gmak..com</email>
</gd:lastModifiedBy>
<gd:lastViewed>2011-04-13T10:44:29.253Z</gd:lastViewed>
<gd:quotaBytesUsed>0</gd:quotaBytesUsed>
<docs:writersCanInvite value="true"/>
<gd:feedLink rel="http://schemas.google.com/acl/2007#accessControlList" href="https://docs.google.com/feeds/default/private/full/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk/acl"/>
<gd:feedLink rel="http://schemas.google.com/docs/2007/revisions" href="https://docs.google.com/feeds/default/private/full/document%3A1j8yrZUCgmanua9Rz7tyBDHsy_vZeUfXfZNAzHatXXqk/revisions"/>
</entry>
...
</feed>
.NET
The following code fetches a list of the currently authenticated user's folders, then prints out the content of the first of them.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a FolderQuery object to retrieve folders.
FolderQuery query = new FolderQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no folders, act accordingly.
}
// TODO: Choose a folder based on your app's needs.
DocumentEntry folder = (DocumentEntry)feed.Entries[0];
// Instantiate a FolderQuery object to retrieve the content of the folder.
FolderQuery contentQuery = new FolderQuery(folder.ResourceId);
// Make a request to the API and get the folder contents.
DocumentsFeed contents = service.Query(contentQuery);
// Iterate through all of the documents returned
foreach (DocumentEntry entry in contents.Entries) {
{
// Print the title of this document to the screen
Console.WriteLine(entry.Title.Text);
Console.WriteLine(entry.Title.Text);
}
}
}
}
Creating collections
To create a collection, send an HTTP POST
request with an <atom:entry>
containing a category element with http://schemas.google.com/g/2005#kind
scheme
and http://schemas.google.com/docs/2007#folder
term. The collection name is
determined by the value of the atom:title element if present. If no atom:title
element is submitted, a default name is chosen.
Here is an example of creating a collection titled Example Collection
.
Protocol
POST https://docs.google.com/feeds/default/private/full
Authorization: <your authorization header here>
Content-Length: 245
Content-Type: application/atom+xml
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#folder"/>
<title>Example Collection</title>
</entry>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentEntry object to be inserted.
DocumentEntry folder = new DocumentEntry();
// Set the folder category.
folder.IsFolder = true;
// Set the folder title.
folder.Title.Text = "Example Collection";
// Make a request to the API and create the folder.
DocumentEntry newFolder = service.Insert(DocumentsListQuery.documentsBaseUri, folder);
}
}
}
If the request is successful, a 201 Created
response is returned along with a
<atom:entry>
describing the collection on the server.
Creating subcollections
Creating a subcollection is similar to creating a normal collection. This
example creates a new subcollection named new subcollection by POST
ing to the
contents link of the target parent collection.
Protocol
POST https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/contents
Authorization: <your authorization header here>
Content-Length: 244
Content-Type: application/atom+xml
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#folder"/>
<title>New subcollection</title>
</entry>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a FolderQuery object to retrieve folders.
FolderQuery query = new FolderQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no folders, act accordingly.
}
// TODO: Choose a folder based on your app's needs.
DocumentEntry folder = (DocumentEntry)feed.Entries[0];
// Instantiate a FolderQuery object to retrieve the content of the folder.
FolderQuery contentQuery = new FolderQuery(folder.ResourceId);
// Instantiate a DocumentEntry object to be inserted.
DocumentEntry subfolder = new DocumentEntry();
// Set the folder category.
subfolder.IsFolder = true;
// Set the folder title.
subfolder.Title.Text = "Example Collection";
// Make a request to the API and create the subfolder.
DocumentEntry newFolder = service.Insert(contentQuery.Uri, subfolder);
}
}
}
Adding a resource to a collection
To add a resource to a collection, send an HTTP POST
request to the contents
feed of the destination collection. The feed URL will have the collection ID
represented by destination_collection_id
in the example below. The request
should contain an <atom:entry>
with the document's <atom:id>
you want to add.
Protocol
POST https://docs.google.com/feeds/default/private/full/folder%3Adestination_collection_id/contents
Authorization: <your authorization header here>
Content-Length: 180
Content-Type: application/atom+xml
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom">
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd</id>
</entry>
.NET
The following code copies the first of the currently authenticated user's documents into the first folder.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a FolderQuery object to retrieve folders.
FolderQuery folderQuery = new FolderQuery();
// Make a request to the API and get all folder.
DocumentsFeed folderFeed = service.Query(folderQuery);
if (folderFeed.Entries.Count == 0)
{
// TODO: There were no folders, act accordingly.
}
// TODO: Choose a folder based on your app's needs.
DocumentEntry folder = (DocumentEntry)folderFeed.Entries[0];
// Instantiate a FolderQuery object to retrieve the content of the folder.
FolderQuery contentQuery = new FolderQuery(folder.ResourceId);
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a document based on your app's needs.
DocumentEntry source = (DocumentEntry)feed.Entries[0];
// Instantiate a DocumentEntry object to be inserted.
DocumentEntry entry = new DocumentEntry();
// Copy the resource ID of the source document
entry.Id = source.Id;
// Make a request to the API and copy the document into the folder.
entry = service.Insert(contentQuery.Uri, entry);
}
}
}
The entry is a word processor document with ID document_id
.
Removing a resource from collection
To remove a resource from a collection, send an HTTP DELETE
request to the
collection content entry's edit
link. The edit
link will have a collection ID
and a resource ID, represented by collection_id
and resource_id
respectively in
the example below.
Protocol
DELETE https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/contents/resource_id
Authorization: <your authorization header here>
.NET
The following code removes the first document from the first of the currently authenticated user's folders.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a FolderQuery object to retrieve folders.
FolderQuery folderQuery = new FolderQuery();
// Make a request to the API and get all folder.
DocumentsFeed folderFeed = service.Query(folderQuery);
if (folderFeed.Entries.Count == 0)
{
// TODO: There were no folders, act accordingly.
}
// TODO: Choose a folder based on your app's needs.
DocumentEntry folder = (DocumentEntry)folderFeed.Entries[0];
// Instantiate a FolderQuery object to retrieve the content of the folder.
FolderQuery contentQuery = new FolderQuery(folder.ResourceId);
// Make a request to the API and get the folder contents.
DocumentsFeed contentFeed = service.Query(contentQuery);
if (contentFeed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a document based on your app's needs.
DocumentEntry entry = (DocumentEntry)contentFeed.Entries[0];
// Make a request to the API and remove the document from the folder.
entry.Delete();
}
}
}
Trashing collections
Trashing a collection moves the collection to the trash.
Protocol
DELETE https://docs.google.com/feeds/default/private/full/folder:12345
If-Match: <ETag or * here>
.NET
The following code removes the first of the currently authenticated user's folders.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a FolderQuery object to retrieve folders.
FolderQuery query = new FolderQuery();
// Make a request to the API and get all folder.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no folders, act accordingly.
}
// TODO: Choose a folder based on your app's needs.
DocumentEntry folder = (DocumentEntry)feed.Entries[0];
service.Delete(folder);
}
}
}
If the collection is trashed successfully, the server responds with an HTTP 200
OK.
Deleting collections
Deleting a collection permanently removes the collection from the user's
documents list. The process for deleting a collection is similar to trashing a
collection, just include the delete=true
parameter.
Protocol
DELETE https://docs.google.com/feeds/default/private/full/resource_id?delete=true
If-Match: <ETag or * here>
.NET
The following code removes the first of the currently authenticated user's folders.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a FolderQuery object to retrieve folders.
FolderQuery query = new FolderQuery();
// Make a request to the API and get all folder.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no folders, act accordingly.
}
// TODO: Choose a folder based on your app's needs.
DocumentEntry folder = (DocumentEntry)feed.Entries[0];
service.Delete(folder, true);
}
}
}
If the collection is deleted successfully, the server responds with an HTTP 200
OK.
Managing sharing permissions of resources via Access Control Lists (ACLs)
Overview of sharing with ACLs
Document and collection sharing is controlled via the access control list feed. Access control lists are just basic lists that show who has access to a given resource. In the ACL feed, the following roles are available for a given document or folder:
- owner
- the owner of the document. As an owner you have the ability to modify the ACL feed, delete the document, etc.
- writer
- a collaborator.
- reader
- a viewer (equivalent to read-only access).
The API supports sharing permissions on multiple levels. These values
correspond to the
- user
- a user's email address.
- group
- a Google Group email address.
- domain
- a Google Apps domain.
- default
- publicly shared with all users.
Additional roles are also supported. A list of potential roles for each
resource type is provided in the metadata feed. One example of an additional
role is the commenter role, which indicates users matching the scope and role
of an ACL entry can also comment on a resource, only if the additional role is
valid for the generic role as defined in the metadata feed. Additional role
values correspond to the
Retrieving the ACL for a document, file, or collection
The ACL feed can be retrieved by accessing the <gd:feedLink>
element of an
entry with rel
attribute http://schemas.google.com/acl/2007#accessControlList
.
Please note that you must use the full projection to receive gd
specific
extension elements in your Documents List feed.
This feed will contain an
Protocol
GET https://docs.google.com/feeds/default/private/full/resource_id/acl
Authorization: <your authorization header here>
The XML snippet below shows the ACL feed for the example document. Note that
the feed contains three ACL entries. The
- document.owner@example.com
- the ACL entry for the document's owner
- a.writer@example.com
- the ACL entry for a collaborator
- a.reader@example.com
- the ACL entry for a reader that can also comment
<?xml version='1.0' encoding='utf-8'?>
<feed xmlns='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'
xmlns:gAcl='http://schemas.google.com/acl/2007'
xmlns:gd='http://schemas.google.com/g/2005'
gd:etag='W/"CUUNSXYyfCp7ImA9WxRVGUo."'>
<id>https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl</id>
<updated>2008-09-03T22:03:04.733Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule' />
<title type='text'>Document Permissions</title>
<link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl' />
<link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl' />
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl' />
<openSearch:totalResults>3</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<entry gd:etag='W/"CUUNSXYyfCp7ImA9WxRVGUo."'>
<id>https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Adocument.owner%40example.com</id>
<updated>2008-09-03T22:03:04.756Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule' />
<title type='text'>Document Permission - document.owner@example.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Adocument.owner%40example.com' />
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Adocument.owner%40example.com' />
<gAcl:role value='owner' />
<gAcl:scope type='user' value='document.owner@example.com' />
</entry>
<entry gd:etag='W/"CUMFQnc4fip7ImA9WxRVGUo."'>
<id>https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.writer%40example.com<>
<updated>2008-09-03T22:03:04.762Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule' />
<title type='text'>Document Permission - a.writer@example.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.writer%40example.com' />
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.writer%40example.com' />
<gAcl:role value='writer' />
<gAcl:scope type='user' value='a.writer@example.com' />
</entry>
<entry gd:etag='W/"CUMASXg8fCp7ImA9WxRVGUo."'>
<id>https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.reader%40example.com</id>
<updated>2008-09-03T22:03:04.763Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule' />
<title type='text'>Document Permission - a.reader@example.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.reader%40example.com' />
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document%3Adocument_id/acl/user%3Aa.reader%40example.com' />
<gAcl:role value='reader'/>
<gAcl:additionalRole value='commenter'/>
<gAcl:scope type='user' value='a.reader@example.com' />
</entry>
</feed>
.NET
The following code fetches a list of the currently authenticated user's documents, and prints out the ACLs of the first of them.
using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Instantiate a AclQuery object to retrieve ACLs.
AclQuery aclQuery = new AclQuery(entry.AccessControlList);
// Make a request to the API and get all ACLs for the document.
AclFeed aclFeed = service.Query(aclQuery);
// Iterate through all of the ACLs returned
foreach (AclEntry acl in aclFeed.Entries)
{
// Print the acl Role to the screen
Console.WriteLine(acl.Role.Value);
// Print the acl Scope type and value to the screen
Console.WriteLine(acl.Scope.Type + " - " + acl.Scope.Value);
}
}
}
}
Updating sharing permissions
The ACL feed accepts GET
, POST
and PUT
requests. To insert a new role into the
ACL feed, simply issue a POST
request.
Protocol
The example below shows how to share a document with a single collaborator:
POST https://docs.google.com/feeds/default/private/full/resource_id/acl
Authorization: <your authorization header here>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gAcl='http://schemas.google.com/acl/2007'>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://schemas.google.com/acl/2007#accessRule'/>
<gAcl:role value='writer'/>
<gAcl:scope type='user' value='new_writer@example.com'/>
</entry>
The new entry is returned on a successful insertion:
201 Created
<entry gd:etag='W/"CUUNSXYyfCp7ImA9WxRVGUo."'>
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com</id>
<updated>2008-09-11T03:10:00.913Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://schemas.google.com/acl/2007#accessRule'/>
<title type='text'>Document Permission - new_writer@example.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/acl/private/full/document:1234abcd/acl/user:new_writer@example.com'/>
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/acl/private/full/document:1234abcd/acl/user:new_writer@example.com'/>
<gAcl:role value='writer'/>
<gAcl:scope type='user' value='new_writer@example.com'/>
</entry>
.NET
The following code shares the first document in the feed with a single collaborator.
using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Instantiate a AclEntry object to update sharing permissions.
AclEntry acl = new AclEntry();
// Set the ACL scope.
acl.Scope = new AclScope("new_writer@example.com", "user");
// Set the ACL role.
acl.Role = new AclRole("writer");
// Insert the new role into the ACL feed.
service.Insert(new Uri(entry.AccessControlList), acl);
}
}
}
To update the entry, we will need to issue an HTTP PUT
request to the entry's
edit
link, which is simply a element, whose rel
attribute is set to
edit. In our case it is:
<link rel='edit'
type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com'/>
The snippet below changes the entry's role to that of a 'reader':
Protocol
PUT https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:gAcl='http://schemas.google.com/acl/2007'
xmlns:gd='http://schemas.google.com/g/2005'
gd:etag='W/"CUUNSXYyfCp7ImA9WxRVGUo."'>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
<gAcl:role value='reader'/>
<gAcl:additionalRole value='commenter'/>
<gAcl:scope type='user' value='new_writer@gmail.com'/>
</entry>
.NET
The following code fetches a list of the currently authenticated user's documents, and changes the ACL's role of the first of them.
using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Instantiate a AclQuery object to retrieve ACLs.
AclQuery aclQuery = new AclQuery(entry.AccessControlList);
// Make a request to the API and get all ACLs for the document.
AclFeed aclFeed = service.Query(aclQuery);
// TODO: Choose a ACL based on your app's needs.
AclEntry acl = (AclEntry)aclFeed.Entries[0];
// Change the ACL's role.
acl.Role = new AclRole("reader");
// Update the ACL entry.
acl.Update();
}
}
}
Email notifications of ACL changes
Creating an ACL entry that shares a document or collection with users will by default notify relevant users via email that they have new access to the document or collection.
However, these emails can be disabled by attaching the
send-notification-emails
parameter to ACL URIs when modifying an ACL. An
example:
POST https://docs.google.com/feeds/default/private/full/document:12345/acl?send-notification-emails=false
Removing sharing permissions
To remove permissions for this user, issue a DELETE
request to the same edit
link that was used for the PUT
request:
Protocol
DELETE https://docs.google.com/feeds/default/private/full/resource_id/acl/user:new_writer@example.com
Authorization: <your authorization header here>
.NET
The following code fetches a list of the currently authenticated user's documents, and deletes the first ACL of the first document.
using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Instantiate a AclQuery object to retrieve ACLs.
AclQuery aclQuery = new AclQuery(entry.AccessControlList);
// Make a request to the API and get all ACLs for the document.
AclFeed aclFeed = service.Query(aclQuery);
// TODO: Choose a ACL based on your app's needs.
AclEntry acl = (AclEntry)aclFeed.Entries[0];
// Delete the ACL entry.
acl.Delete();
}
}
}
Sharing collections
To share a collection, provide a collection resource ID instead of a document ID. This example grants everyone on the domain example.com the ability to read the collection's content:
POST https://docs.google.com/feeds/default/private/full/folder%3Acollection_id/acl
Authorization: <your authorization header here>
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:gAcl='http://schemas.google.com/acl/2007'>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://schemas.google.com/acl/2007#accessRule'/>
<gAcl:role value='reader'/>
<gAcl:scope type='domain' value='example.com'/>
</entry>
Sharing resources with a group or Google Apps domain
Similar to sharing with a single user, you can share resources across a group or domain if you have a Google Apps domain, or with all Google Docs users.
Sharing to a group email address
<gAcl:scope type="group" value="group@example.com"/>
Sharing to an entire domain
<gAcl:scope type="domain" value="example.com"/>
Sharing resources with the public (the rest of the Internet)
Doing this shares a resource to all Google users, e.g. "the public".
<gAcl:scope type="default"/>
Sharing resources with authorization keys
All Google Docs ACLs have a key set by Google Docs. The key is retrievable from a Documents List Entry. The key is used to grant access for users to certain documents, but this is different than sharing documents with users directly, as when using a key, users do not have to be added to an ACL directly.
The granting of reader or writer roles may be conditional based on the user
having or not having a key. An example would be that all users in a domain with
a certain key will have write permissions to a document. One key is assigned
per ACL, even if there are multiple entries in the ACL. This key is generated
by Google Docs, and cannot be modified. Keys are specified using
Sharing to all domain users who have the specified key, and giving those users write permission.
Protocol
<entry>
<gAcl:withKey key='[ACL KEY]'><gAcl:role value='writer' /></gAcl:withKey>
<gAcl:scope type='domain' value='example.com' />
</entry>
.NET
The following code shares the first document in the feed with all domain users who have the specified key, and gives those users write permission.
using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Instantiate a AclEntryWithKey object to share with keys.
AclEntryWithKey acl = new AclEntryWithKey();
// Set the ACL scope.
acl.Scope = new AclScope("example.com", "domain");
// Instantiate a AclWithKey object to specify a key.
AclWithKey withKey = new AclWithKey("[ACL KEY]");
// Set the ACL role.
withKey.Role = new AclRole("writer");
// Set the WithKey property of the AclEntryWithKey element.
acl.WithKey = withKey;
// Insert the new role into the ACL feed.
service.Insert(new Uri(entry.AccessControlList), acl);
}
}
}
Sharing to all Google Docs users who have the specified key, and giving those users read permission:
Protocol
<entry>
<gAcl:withKey key='[ACL KEY]'><gAcl:role value='reader' /></gAcl:withKey>
<gAcl:scope type='default' />
</entry>
.NET
The following code shares the first document in the feed with all Google Docs users who have the specified key, and gives those users read permission.
using System;
using Google.GData.AccessControl;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate a DocumentsListQuery object to retrieve documents.
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
// TODO: There were no documents, act accordingly.
}
// TODO: Choose a resource based on your app's needs.
DocumentEntry entry = (DocumentEntry)feed.Entries[0];
// Instantiate a AclEntryWithKey object to share with keys.
AclEntryWithKey acl = new AclEntryWithKey();
// Set the ACL scope.
acl.Scope = new AclScope("", "default");
// Instantiate a AclWithKey object to specify a key.
AclWithKey withKey = new AclWithKey("[ACL KEY]");
// Set the ACL role.
withKey.Role = new AclRole("reader");
// Set the WithKey property of the AclEntryWithKey element.
acl.WithKey = withKey;
// Insert the new role into the ACL feed.
service.Insert(new Uri(entry.AccessControlList), acl);
}
}
}
Batching ACL requests
Batch processing gives the ability to execute multiple operations in one request, rather than sending a single request per operation.
The server performs as many of the requested changes as possible, and returns status information about the success or failure of each operation. Further information about batch processing is given in Batch Processing with Google Data APIs.
When generating an ACL feed for a batch request, every entry except those being
created must have an
The following example demonstrates how to query, insert, update and delete ACL entries of a resource.
POST https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/batch
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:gAcl="http://schemas.google.com/acl/2007"
xmlns:batch="http://schemas.google.com/gdata/batch">
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/acl/2007#accessRule"/>
<entry>
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:owner@example.com</id>
<batch:operation type="query"/>
</entry>
<entry>
<batch:id>1</batch:id>
<batch:operation type="insert"/>
<gAcl:role value="writer"/>
<gAcl:scope type="user" value="new_writer@example.com"/>
</entry>
<entry>
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:old_writer@example.com</id>
<batch:operation type="update"/>
<gAcl:role value="reader"/>
<gAcl:scope type="user" value="old_writer@example.com"/>
</entry>
<entry>
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:deprecated_writer@example.com</id>
<batch:operation type="delete"/>
<gAcl:role value="writer"/>
<gAcl:scope type="user" value="deprecated_writer@example.com"/>
</entry>
</feed>
The returned feed will contain one result entry for each operation.
<?xml version='1.0' encoding='utf-8'?>
<feed xmlns:atom='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
xmlns:gAcl='http://schemas.google.com/acl/2007'
xmlns:batch='http://schemas.google.com/gdata/batch'>
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl</id>
<updated>2009-03-06T09:13:23.382Z</updated>
<title type='text'>Batch Feed</title>
<link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl'/>
<link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl'/>
<link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/batch'/>
<entry>
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:owner@example.com</id>
<updated>2009-03-06T09:13:23.381Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
<title type='text'>Document Permission - owner@example.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:owner@example.com'/>
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:owner@example.com'/>
<gAcl:role value='owner'/>
<gAcl:scope type='user' value='owner@example.com'/>
<batch:status code='200' reason='Success'/>
<batch:operation type='query'/>
</entry>
<entry>
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com</id>
<updated>2009-03-06T09:13:25.381Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
<title type='text'>Document Permission - new_writer@example.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com'/>
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:new_writer@example.com'/>
<gAcl:role value='writer'/>
<gAcl:scope type='user' value='new_writer@example.com'/>
<batch:id>1</batch:id>
<batch:status code='201' reason='Created'/>
<batch:operation type='insert'/>
</entry>
<entry>
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:old_writer@example.com</id>
<updated>2009-03-06T09:13:27.737Z</updated>
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/acl/2007#accessRule'/>
<title type='text'>Document Permission - old_writer@example.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:old_writer@example.com'/>
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:old_writer@example.com'/>
<gAcl:role value='reader'/>
<gAcl:scope type='user' value='old_writer@example.com'/>
<batch:status code='200' reason='Success'/>
<batch:operation type='update'/>
</entry>
<entry>
<id>https://docs.google.com/feeds/default/private/full/document:1234abcd/acl/user:deprecated_writer@example.com</id>
<updated>2009-03-06T09:13:29.743Z</updated>
<title type='text'>Deleted</title>
<content type='text'>Deleted</content>
<batch:status code='200' reason='Success'/>
<batch:operation type='delete'/>
</entry>
</feed>
Managing archives of documents and files
The archive feed can be used to export resources as a .zip file. Your client determines the desired export format for each type of resource and downloads the archive once the process has finished.
Creating archives of documents and files
To initiate an archive request, send an authenticated POST
request to the
archive feed's URI:
https://docs.google.com/feeds/default/private/archive
The body of the request contains data which controls the archive operation and, optionally, a list of resource IDs to archive. If no resource IDs are contained in the request body, query parameters from the URL (if any) is used to select the items to include in the archive. If the request body contains one or more resource IDs, query parameters from the URL are ignored.
The following example archives three documents, a PDF, and a collection's contents, selects their export format, and emails 'user@gmail.com' when the archive operation has finished.
Protocol
POST https://docs.google.com/feeds/default/private/archive
Authorization: <your authorization header here>
Content-Length: 457
Content-Type: application/atom+xml
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
<docs:archiveResourceId>document:0A1234567890</docs:archiveResourceId>
<docs:archiveResourceId>spreadsheet:0A1234567890</docs:archiveResourceId>
<docs:archiveResourceId>presentation:0A1234567890</docs:archiveResourceId>
<docs:archiveResourceId>pdf:0A12sdf</docs:archiveResourceId>
<docs:archiveResourceId>folder:0A1234567890</docs:archiveResourceId>
<docs:archiveConversion source='application/vnd.google-apps.document' target='application/msword'/>
<docs:archiveConversion source='application/vnd.google-apps.spreadsheet' target='text/csv'/>
<docs:archiveConversion source='application/pdf' target='application/pdf'/>
<docs:archiveNotify>user@gmail.com</docs:archiveNotify>
</entry>
The response contains information about the archive.
<?xml version='1.0' encoding='utf-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:docs='http://schemas.google.com/docs/2007'
xmlns:gd='http://schemas.google.com/g/2005'>
<id>
https://docs.google.com/feeds/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA</id>
<published>2010-11-18T18:34:06.981Z</published>
<updated>2010-11-18T18:34:07.763Z</updated>
<app:edited xmlns:app='http://www.w3.org/2007/app'>
2010-11-18T18:34:07.763Z</app:edited>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://schemas.google.com/docs/2007#archive'
label='archive' />
<title>Document Archive - someuser@somedomain.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
<author>
<name>someuser</name>
<email>someuser@somedomain.com</email>
</author>
<docs:archiveNotify>someuser@somedomain.com</docs:archiveNotify>
<docs:archiveStatus>flattening</docs:archiveStatus>
<docs:archiveResourceId>
0Adj-hQNOVsTFSNDEkdk2221OTJfMWpxOGI5OWZu</docs:archiveResourceId>
<docs:archiveResourceId>
0Adj-hQNOVsTFZGZodGs2O72NFMllMQDN3a2Rq</docs:archiveResourceId>
<docs:archiveConversion source='application/vnd.google-apps.document'
target='text/plain' />
</entry>
.NET
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate an ArchiveEntry object to initiate an archive request.
ArchiveEntry entry = new ArchiveEntry();
// Add the IDs of the resources to be included in the archive.
entry.ArchiveResourceIds.Add(new ArchiveResourceId("document:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("spreadsheet:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("presentation:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("pdf:0A12sdf"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("folder:0A1234567890"));
// Specify the conversion formats for each entry.
entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.document", "application/msword"));
entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.spreadsheet", "text/csv"));
entry.ArchiveConversions.Add(new ArchiveConversion("application/pdf", "application/pdf"));
// Set the email address of the user to be notified.
entry.ArchiveNotify = "user@gmail.com";
// Send the archive request to the API.
service.Insert(DocumentsListQuery.archiveUri, entry);
}
}
}
The response entry from the POST
request will reflect the user provided
elements as well as standard elements added by the server.
The following is an example of how to use query parameters to archive all resources matching the query. Note that although no resource IDs are specified in the request, they will come back in the response, so that you know exactly which items are in the archive.
POST https://docs.google.com/feeds/default/private/archive?q=title:test
Authorization: <your authorization header here>
Content-Length: 457
Content-Type: application/atom+xml
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
<docs:archiveConversion source='application/vnd.google-apps.document' target='application/msword'/>
<docs:archiveConversion source='application/vnd.google-apps.spreadsheet' target='text/csv'/>
<docs:archiveConversion source='application/pdf' target='application/pdf'/>
<docs:archiveNotify>user@gmail.com</docs:archiveNotify>
</entry>
The response is:
<?xml version='1.0' encoding='utf-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:docs='http://schemas.google.com/docs/2007'
xmlns:gd='http://schemas.google.com/g/2005'>
<id>
https://docs.google.com/feeds/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA</id>
<published>2010-11-18T18:34:06.981Z</published>
<updated>2010-11-18T18:34:07.763Z</updated>
<app:edited xmlns:app='http://www.w3.org/2007/app'>
2010-11-18T18:34:07.763Z</app:edited>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://schemas.google.com/docs/2007#archive'
label='archive' />
<title>Document Archive - someuser@somedomain.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
<author>
<name>someuser</name>
<email>someuser@somedomain.com</email>
</author>
<docs:archiveNotify>someuser@somedomain.com</docs:archiveNotify>
<docs:archiveStatus>flattening</docs:archiveStatus>
<docs:archiveResourceId>
0Adj-hQNOVsTFSNDEkdk2221OTJfMWpxOGI5OWZu</docs:archiveResourceId>
<docs:archiveResourceId>
0Adj-hQNOVsTFZGZodGs2O72NFMllMQDN3a2Rq</docs:archiveResourceId>
<docs:archiveConversion source='application/vnd.google-apps.document'
target='text/plain' />
</entry>
Explanation of archive feed elements
Element | Example | Description |
---|---|---|
id |
https://docs.google.com/feeds/archive/228jZrUfn0... | The unique URL used to identify this archive and to retrieve this archive entry again. The bold portion of the above example is the archive-id used throughout this documentation. |
docs:archiveResourceId |
document:0A1234567890 | The resource ID of an item in the user's doclist, repeated for each document to archive. The server will accept both typed and untyped resource IDs, but will return only untyped resource IDs in the response feed. Tip: Collection resource IDs (e.g. folder:id) will cause the contents of the collection to be included in the archive. |
docs:archiveConversion |
source="text/plain" target="application/pdf" | A map of desired export formats. If a MIME type is not recognized, it will not be used in generating the archive. If an element does not give a target format for a `docs:archiveConversion` element, the element will not be used in generating the archive. Default target MIME types are used if you don't specify a target MIME type for an item that is added to the archive. This parameter is repeated for each for each unique MIME type of an item to be included in the archive. Use source="*" for a default archiveConversion specification. |
docs:archiveNotify | user@gmail.com | Optional. An email address to notify when an archive operation is complete and the archive is ready for download. |
MIME types for native Google document formats
- Google Doc
- application/vnd.google-apps.document
- Google Spreadsheet
- application/vnd.google-apps.spreadsheet
- Google Form
- application/vnd.google-apps.form
- Google Presentation
- application/vnd.google-apps.presentation
- Google Drawing
- application/vnd.google-apps.drawing
Getting the status of an archive
A GET
request returns the status of an archive. The resulting entry contains
elements which provide information (including completion status) about the
archive operation.
The entry returned contains these elements:
Element | Example | Description |
---|---|---|
docs:archiveResourceId |
document:0A1234567890 | The resource ID of an item, repeated for each resource to archive. The server accepts both typed and untyped resource IDs, but only returns untyped resource IDs in the response feed. Tip: Collection resource IDs (e.g. folder:id) cause the contents of the collection to be included in the archive. |
published |
2009-11-05T05:59:58.615Z | Time the archive was started |
content |
type="application/zip" src="http://docs.google.com/download/xyz" | URL where the archive can be downloaded |
docs:archiveStatus |
queued, flattening, archiving, finished, aborted, expired | Status of the archive |
docs:archiveComplete |
2009-11-05T05:59:58.615Z | Time the archive is estimated to complete or was completed |
gd:quotaBytesUsed |
50000000 | Size of the completed archive in bytes |
docs:archiveTotal |
10 | Number of resources in the archive |
docs:archiveTotalComplete |
5 | Number of resources processed so far |
docs:archiveTotalFailure |
1 | Number of resources processed which failed to be archived |
docs:archiveFailure |
document:12345 | ID of failed resource. Repeated for each failure. |
docs:archiveNotifyStatus |
none, sent, failed | Status of the email notification |
docs:archiveConversion |
source="text/plain" target="application/pdf" | See the previous section about docs:archiveConversion under Creating archives of documents and files. |
docs:archiveNotify | user@gmail.com | Optional. An email address to notify when an archive operation is complete. |
Protocol
When the archive operation is not complete:
GET https://docs.google.com/feeds/default/private/archive/<archive-id>
Authorization: <your authorization header here>
The response is:
200 OK
<?xml version='1.0' encoding='utf-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:docs='http://schemas.google.com/docs/2007'
xmlns:gd='http://schemas.google.com/g/2005'>
<id>
https://docs.google.com/feeds/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA</id>
<published>2010-11-18T18:34:06.981Z</published>
<updated>2010-11-18T19:13:31.266Z</updated>
<app:edited xmlns:app='http://www.w3.org/2007/app'>
2010-11-18T19:13:31.266Z</app:edited>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://schemas.google.com/docs/2007#archive'
label='archive' />
<title>Document Archive - someuser@somedomain.com</title>
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
<author>
<name>someuser</name>
<email>someuser@somedomain.com</email>
</author>
<docs:archiveNotify>someuser@somedomain.com</docs:archiveNotify>
<docs:archiveStatus>archiving</docs:archiveStatus>
<docs:archiveResourceId>0Adj-hQNOVsTFSNDEkdk2221OTJfMWpxOGI5OWZu</docs:archiveResourceId>
<docs:archiveResourceId>0Adj-hQNOVsTFZGZodGs2O72NFMllMQDN3a2Rq</docs:archiveResourceId>
<docs:archiveConversion source='application/vnd.google-apps.document' target='text/plain' />
</entry>
When the archive operation is complete:
GET https://docs.google.com/feeds/default/private/archive/<archive-id>
Authorization: <your authorization header here>
The response will be:
<?xml version='1.0' encoding='utf-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'
xmlns:docs='http://schemas.google.com/docs/2007'
xmlns:gd='http://schemas.google.com/g/2005'>
<id>
https://docs.google.com/feeds/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA</id>
<published>2010-11-18T18:34:06.981Z</published>
<updated>2010-11-18T19:13:31.266Z</updated>
<app:edited xmlns:app='http://www.w3.org/2007/app'>
2010-11-18T19:13:31.266Z</app:edited>
<category scheme='http://schemas.google.com/g/2005#kind'
term='http://schemas.google.com/docs/2007#archive'
label='archive' />
<title>Document Archive - someuser@somedomain.com</title>
<content type='application/zip' src='https://doc-00-90-docs.googleusercontent.com/docs/secure/he0nmogeutv9f47fuhdm5052r4methcr/82t504tsh5roodr6f8qr4lpdlng1hkjk/1290103200000/15266010465028272046/15266010465028272046/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA?a=docs-archive-2010-11-18.zip&ai=-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA&ap=grOCTZLfQ5X0EArImf6Qfdg4ZlilxR6JNmObNJCbc6Q&h=18423295174435396830&gd=true' />
<link rel='self' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
<link rel='edit' type='application/atom+xml'
href='https://docs.google.com/feeds/default/private/archive/-228SJEnnmwemsiDLLxmGeGygWrvW1tMZHHg6ARCy3Uj3SMH1GHlJ2scb8BcHSDDDUosQAocwBQOAKHOq3-0gmKA' />
<author>
<name>someuser</name>
<email>someuser@somedomain.com</email>
</author>
<docs:archiveNotify>someuser@somedomain.com</docs:archiveNotify>
<docs:archiveStatus>finished</docs:archiveStatus>
<gd:quotaBytesUsed>308</gd:quotaBytesUsed>
<docs:archiveNotifyStatus>sent</docs:archiveNotifyStatus>
<docs:archiveComplete>2010-11-18T18:34:09.679Z</docs:archiveComplete>
<docs:archiveTotal>2</docs:archiveTotal>
<docs:archiveTotalComplete>2</docs:archiveTotalComplete>
<docs:archiveTotalFailure>0</docs:archiveTotalFailure>
<docs:archiveResourceId>0Adj-hQNOVsTFSNDEkdk2221OTJfMWpxOGI5OWZu</docs:archiveResourceId>
<docs:archiveResourceId>0Adj-hQNOVsTFZGZodGs2O72NFMllMQDN3a2Rq</docs:archiveResourceId>
<docs:archiveConversion source='application/vnd.google-apps.document' target='text/plain' />
</entry>
.NET
The following code sends an archive request, then fetches its status and prints the value of the archiveStatus property.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate an ArchiveEntry object to initiate an archive request.
ArchiveEntry entry = new ArchiveEntry();
// Add the IDs of the resources to be included in the archive.
entry.ArchiveResourceIds.Add(new ArchiveResourceId("document:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("spreadsheet:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("presentation:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("pdf:0A12sdf"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("folder:0A1234567890"));
// Specify the conversion formats for each entry.
entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.document", "application/msword"));
entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.spreadsheet", "text/csv"));
entry.ArchiveConversions.Add(new ArchiveConversion("application/pdf", "application/pdf"));
// Set the email address of the user to be notified.
entry.ArchiveNotify = "user@gmail.com";
// Send the archive request to the API.
entry = service.Insert(DocumentsListQuery.archiveUri, entry);
// Instantiate an ArchiveQuery object to retrieve archives.
ArchiveQuery query = new ArchiveQuery(archiveId);
// Make a request to the API and get the archive feed.
ArchiveFeed feed = service.Query(query);
if (feed.Entries.Count == 0)
{
throw new Exception("The archive feed should always contain an entry");
}
// The archive feed contains a single entry.
entry = (ArchiveEntry)feed.Entries[0];
// Print the status of the archive operation.
Console.WriteLine(entry.ArchiveStatus);
}
}
}
Generated archives, although they are ZIP files, will not show up in a user's documents list.
Generated archives are periodically purged, and should be fetched as soon as
possible after they are created. If you request an archive that has been
purged, a 410 Gone
response is given, and the archive must be created again.
Updating the notification email address of an archive
A PUT
request changes the archive notification email address. All elements
returned in a GET
may be sent to the server, however only the notification
email address is examined and changed. A PUT
request on an archive in one of
the completed states (finished, aborted, expired) results in a 410 Gone
response.
Example of changing an archive's notification email:
Protocol
PUT https://docs.google.com/feeds/default/private/archive/
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007"
xmlns:gd="http://schemas.google.com/g/2005">
...
<docs:archiveNotify>different_user@example.com</docs:archiveNotify>
</entry>
.NET
The following code sends an archive request, then updates its notification email address.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate an ArchiveEntry object to initiate an archive request.
ArchiveEntry entry = new ArchiveEntry();
// Add the IDs of the resources to be included in the archive.
entry.ArchiveResourceIds.Add(new ArchiveResourceId("document:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("spreadsheet:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("presentation:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("pdf:0A12sdf"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("folder:0A1234567890"));
// Specify the conversion formats for each entry.
entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.document", "application/msword"));
entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.spreadsheet", "text/csv"));
entry.ArchiveConversions.Add(new ArchiveConversion("application/pdf", "application/pdf"));
// Set the email address of the user to be notified.
entry.ArchiveNotify = "user@gmail.com";
// Send the archive request to the API.
entry = service.Insert(DocumentsListQuery.archiveUri, entry);
// Set the new notification email address.
entry.ArchiveNotify = "different_user@example.com";
// Make a request to the API and update the archive.
entry.Update();
}
}
Aborting an archive in the process of being generated
A DELETE
request aborts an archive operation. A DELETE
request on an archive in
one of the completed states (finished, aborted, expired) results in a 410 Gone
response.
Example of aborting an in-progress archive request:
Protocol
DELETE https://docs.google.com/feeds/default/private/archive/
.NET
The following code sends an archive request, then aborts the operation.
using System;
using Google.GData.Client;
using Google.GData.Documents;
namespace MyDocumentsListIntegration
{
class Program
{
static void Main(string[] args)
{
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
// TODO: Authorize the service object for a specific user (see Authorizing requests)
// Instantiate an ArchiveEntry object to initiate an archive request.
ArchiveEntry entry = new ArchiveEntry();
// Add the IDs of the resources to be included in the archive.
entry.ArchiveResourceIds.Add(new ArchiveResourceId("document:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("spreadsheet:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("presentation:0A1234567890"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("pdf:0A12sdf"));
entry.ArchiveResourceIds.Add(new ArchiveResourceId("folder:0A1234567890"));
// Specify the conversion formats for each entry.
entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.document", "application/msword"));
entry.ArchiveConversions.Add(new ArchiveConversion("application/vnd.google-apps.spreadsheet", "text/csv"));
entry.ArchiveConversions.Add(new ArchiveConversion("application/pdf", "application/pdf"));
// Set the email address of the user to be notified.
entry.ArchiveNotify = "user@gmail.com";
// Send the archive request to the API.
entry = service.Insert(DocumentsListQuery.archiveUri, entry);
// Make a request to the API and abort the operation.
entry.Delete();
}
}