Johan Euphrosine
June 2011
Updated January 2013 by Danny Hermes
This article shows how to build a simple Python App Engine application that retrieves a list of tasks with the Google Tasks API. Google Tasks stores tasks that users enter via GMail, their mobile device, or calendar. The Google Tasks API provides developers with a powerful set of API endpoints for searching, reading, and updating Google Tasks content and metadata.
During this tutorial you will learn how to:
- Create a simple App Engine app using the Google APIs Client Library for Python.
- Provide Google Tasks users a mechanism to authorize your app to access their tasks.
- Make authorized requests to the Google Tasks API.
The source code for the final step of this tutorial is available in Google APIs Client Library for Python samples directory.
Before You Start
- Install Google App Engine SDK for Python for local testing and deployment of your application.
- Install Mercurial to check out a repository.
- Get the Google APIs Client Library for Python. This library supports the Google Tasks API.
Step 1: Create Your App Engine Project
First, you need to create a web application:
-
Create a new directory named
mytasks. This will contain your new application. -
In the
mytasksdirectory, create a file namedapp.yamlwith the following contents:application: mytasks version: 1 runtime: python27 api_version: 1 threadsafe: true handlers: - url: .* script: main.applicationFor more information, see Python Application Configuration.
-
In the
mytasksdirectory, create a file namedmain.pywith the following contents:import webapp2 class MainHandler(webapp2.RequestHandler): def get(self): self.response.write('Hello App Engine!') application = webapp2.WSGIApplication([('/', MainHandler)], debug=True) -
Run
dev_appserver.py app.yaml. -
Point your browser to http://localhost:8080.
-
You will see
Hello App Engine!in the browser window.
Step 2: Enabling Your Application for the Tasks API
Next, you need to enable your application to use the Tasks API. The following
instructions take you through the process for an app named mytasks:
To get started using Tasks API, you need to first create or select a project in the Google Developers Console and enable the API. Using this link guides you through the process and activates the Tasks API automatically.
Alternatively, you can activate the Tasks API yourself in the Developers Console by doing the following:
- Go to the Google Developers Console.
- Select a project, or create a new one.
- In the sidebar on the left, expand APIs & auth. Next, click APIs. In the list of APIs, make sure the status is ON for the Tasks API.
- In the sidebar on the left, select Credentials.
In either case, you end up on the Credentials page and can create your project's credentials from here.
From the Credentials page, click Create new Client ID under the OAuth heading to create your OAuth 2.0 credentials. Your application's client ID, email address, client secret, redirect URIs, and JavaScript origins are in the Client ID for web application section. This section also has several buttons:
- An Edit Settings button, which lets you edit redirect URIs and edit JavaScript origins settings.
- A Reset Secret button.
- A Download JSON button, for adding JSON resources.
- A Delete button.
client ID and client secret from the Google Developers Console.
In the mytasks directory, create a new file named settings.py. Copy the following
test into the new file, replacing the 'client id' and the 'client secret' with those
from your registered application.
CLIENT_ID='PASTE_YOUR_GENERATED_CLIENT_ID_HERE' CLIENT_SECRET='PASTE_YOUR GENERATED_CLIENT_SECRET_HERE' SCOPE='https://www.googleapis.com/auth/tasks'
This file will be imported and used by your authorization code. Replace the above placeholder values using those you've just generated.
Step 3: Add the Google Tasks API
Next, we need to import and use Google API Python client modules in order to retrieve the list of tasks for the current user.
-
Follow the Google APIs Client Library for Python install instructions.
-
Download the file named
google-api-python-client-gae-N.M.zipfrom the list of downloads. -
Unzip that file into the
mytasksdirectory. -
Replace the current contents of
main.pywith the following:import webapp2 from apiclient.discovery import build from oauth2client.appengine import OAuth2Decorator import settings decorator = OAuth2Decorator(client_id=settings.CLIENT_ID, client_secret=settings.CLIENT_SECRET, scope=settings.SCOPE) service = build('tasks', 'v1') class MainHandler(webapp2.RequestHandler): @decorator.oauth_required def get(self): tasks = service.tasks().list(tasklist='@default').execute( http=decorator.http()) self.response.write('<html><body><ul>') for task in tasks['items']: self.response.write('<li>%s</li>' % task['title']) self.response.write('</ul></body><html>') application = webapp2.WSGIApplication([ ('/', MainHandler), (decorator.callback_path, decorator.callback_handler()), ], debug=True) -
Go to http://localhost:8080.
-
Login.
-
Authorize. After authorizing, you will see the list of tasks from the default task list of this user.
You've now completed your first Google Tasks API application and you are ready to deploy to Google App Engine.
Step 4: Deploy Your Application
Finally, we will create a new Application Identifier for your app, and deploy it to Google App Engine.
-
Go to the Google App Engine Administration Console.
-
Create a new application or choose an existing one to re-use.
-
Choose an Application Identifier.
-
Update
applicationinapp.yamlwith your new Application Identifier.application: your_app_id version: 1 runtime: python27 api_version: 1 threadsafe: true handlers: - url: .* script: main.application -
Go to the Google Developers Console. Select the application from the list.
-
In the sidebar on the left, click APIs and auth.
-
Click Credentials.
-
Add the following Authorized Redirect URIs to the Client ID for web application panel, replacing
your_app_idwith your Application Identifier.http://your_app_id.appspot.com/oauth2callback https://your_app_id.appspot.com/oauth2callback
-
Run
google_appengine/appcfg.py update mytasks/. -
Go to
https://your_app_id.appspot.com. -
Login.
-
Authorize. After authorizing, you should see the list of tasks from the default task list of this user.
Congratulations! You've just deployed your first Google Tasks API application to Google App Engine.
Bonus Task: Add Landing Page, Style and Template
Providing a landing page for your application is also important for making a less jarring OAuth experience, letting the user know up front why they are being directed into the OAuth flow before it begins as documented in the Google APIs Client Library for Python documentation.
You need to choose scopes wisely and not request for more permission than your application actually needs.
Lastly, if you'd like to add some polish, add some CSS styling to your HTML. You can use ours below, or create your own.
-
Update
settings.pyby changing the scope toreadonly:CLIENT_ID='PASTE_YOUR_GENERATED_CLIENT_ID_HERE' CLIENT_SECRET='PASTE_YOUR GENERATED_CLIENT_SECRET_HERE' SCOPE='https://www.googleapis.com/auth/tasks.readonly'
-
Update
main.pywith the following contents:import webapp2 from webapp2_extras import jinja2 from apiclient.discovery import build from oauth2client.appengine import OAuth2Decorator import settings decorator = OAuth2Decorator(client_id=settings.CLIENT_ID, client_secret=settings.CLIENT_SECRET, scope=settings.SCOPE) service = build('tasks', 'v1') class MainHandler(webapp2.RequestHandler): def render_response(self, template, **context): renderer = jinja2.get_jinja2(app=self.app) rendered_value = renderer.render_template(template, **context) self.response.write(rendered_value) @decorator.oauth_aware def get(self): if decorator.has_credentials(): result = service.tasks().list(tasklist='@default').execute( http=decorator.http()) tasks = result.get('items', []) for task in tasks: task['title_short'] = truncate(task['title'], 26) self.render_response('index.html', tasks=tasks) else: url = decorator.authorize_url() self.render_response('index.html', tasks=[], authorize_url=url) def truncate(s, l): return s[:l] + '...' if len(s) > l else s application = webapp2.WSGIApplication([ ('/', MainHandler), (decorator.callback_path, decorator.callback_handler()), ], debug=True) -
In the
mytasksdirectory, create a file namedtemplates/index.htmlwith the following contents:<!doctype html> <html> <head> <link href="/css/style.css" rel="stylesheet" type="text/cs"> <link href="http://fonts.googleapis.com/css?family=Coming+Soon:regular" rel="stylesheet" type="text/css"> </head> <body> <ul id="tasklist"> {% if tasks|length == 0 %} <li> <span class="check"> <span> </span> </span> {% if authorize_url %} <a class="title" title="Grant read access to your tasks" href="{{ authorize_url }}">Grant Access</a> {% else %} <a class="title" title="Add more tasks in Gmail" href="http://mail.google.com/">Add More Tasks</a> {% endif %} </li> {% endif %} {% for task in tasks %} <li class="{{ task.status }}"> <span class="check"> <span> {% if task.status == "completed" %} ✓ {% else %} {% endif %} </span> </span> <a class="title" title="{{ task.title }}">{{ task.title_short }}</a> </li> {% endfor %} </ul> </body> </html> -
In the
mytasksdirectory, create a file namedcss/style.csswith the following contents:body { width: 600px; margin: auto; margin-top: 48px; margin-bottom: 48px; font-family: 'Coming Soon', serif; font-size: 35px; } ul { -moz-border-radius: 20px; -webkit-border-radius: 20px; border-radius: 20px; background-color: #f8f6c6; background-image: -webkit-linear-gradient(#fdfce8, #f8f6c6); list-style-type: none; padding: 0; margin: 0; border: 5px solid #e3e2be; -moz-box-shadow: 8px 8px 8px #ccc; -webkit-box-shadow: 8px 8px 8px #ccc; box-shadow: 8px 8px 8px #ccc; } li { padding-left: 20px; border-bottom: 4px solid #e3e2be; } li .check { display: block; float: left; border-right: 8px solid #e3e2be; padding-right: 20px; width: 20px; } li .title { margin-left: 4px; padding-left: 20px; border-left: 4px solid #e3e2be; color: black; text-decoration: none; } li:last-child { border-bottom: none; } -
Update
app.yamlwith the following contents:application: mytasks version: 1 runtime: python27 api_version: 1 threadsafe: true handlers: - url: /css static_dir: css - url: .* script: main.application libraries: - name: jinja2 version: latest -
Deploy your application by following the instructions in Step 4.
-
Go to
https://your_app_id.appspot.comYou should see a well-designed lists of tasks.