ONLamp.com    
 Published on ONLamp.com (http://www.onlamp.com/)
 See this if you're having trouble printing code examples


Getting Started with the Google App Engine

by Noah Gift
05/20/2008

INTRODUCTION

It's a bird, it's a plane, no it is Guido Van Rossum and the App Engine Team. After cranking through writing an instructional application this weekend using Google App Engine, I have to say I am really impressed. In fact my exact thought are "Holy $!ck, this is awesome!

If you haven't heard about Google App Engine yet, in a nutshell, Google has opened up their infrastructure to the masses in the form of a Python API. If you are a Python developer this is obviously a very significant development as it means you can easily hit the ground running. If you come from another language such as PHP, Java, Ruby, or Perl, there is no reason why you can't get started in a day or so in writing applications in Python. Python is quite easy to learn if you already know another language, and it has a deserved reputation for being one of the easiest languages to learn period.

In this article, we are going to "crib" some of the documentation for Google App Engine, and then proceed to actually build an application using the SDK. There is a live version of the application for this article that you can view here:Greedy Coin App Engine.

CRIB SHEET

Developer API's

First off let's take a look at some of the exposed Developer API's:

Application Quotas

Each application is subject to a set of resource quotas that control how much CPU, Bandwidth and storage space it can consume.

It can handle sudden spikes in traffic by ramping up demand. If the quota is exceeded you will get 403 errors.

You can reference more here: http://code.google.com/appengine/articles/quotas.html

Running Django on Google App Engine

You can launch a Django application using a WSGI handler, but a few modifications will need to be made. You can reference them here:

http://code.google.com/appengine/articles/django.html

Configuring Access

By default Google App Engine lets you share your application with anyone with a Google Account. You can restrict this to access to only Google App domain accounts though.

Configuring Logging

Python has a sweet logging module, and Google App Engine directly integrates with it by allowing you to log 5 levels of severity. These logs get funneled to the Administration Console at:

http://appengine.google.com/admin

You can reference more here:

http://code.google.com/appengine/articles/logging.html

You can also view a debug log by attaching a ?debug to the end of a URL path.

Sample Applications and Code

You can download many sample applications here by doing a svn checkout:

http://code.google.com/p/google-app-engine-samples/source/checkout

Form Validation

There is a custom version of Django's form validation framework that works with the Google datastore.

This means it is easy to write forms that validate data correctly.

Datastore

Flexible, schema-less object database, perhaps influenced byZODB to some degree, but apparently also in the spirit of JQuery and FBQL.

    SELECT * FROM Story
             WHERE title = 'App Engine Launch'
               AND author = :current_user
               AND rating >= 10
             ORDER BY rating, created DESC

One gotcha is that the Datastore does not support joins, as this is one of the performance bottlenecks with a Relational Databases. In my opinion this API is one of the hidden Gems of the Google App Engine API.

Reference: http://code.google.com/appengine/docs/datastore/overview.html

MINI-TUTORIAL

Building an Application: Greedy Coin Changer

Intro

Recently I wrote a blog post about a Greedy Coin Changing Algorithm. I decided to take that command line tool and convert it into a Google App Engine application for this article. This happens to be the way I tend to write a lot of small web applications, which may be weird for some people, but I happen to be a command line tool kind of guy.

Before we get started I wanted to point a couple of things out. First, this tutorial has a fully functioning application you can play with, along with the source code. If you are "uber" , you might just want to check it out of svn and use it as boiler plate for your own creation. At the bottom of this article in the references section there is a link to the application and the subversion repository where you can check out the source code.

Second, this is more condensed, pragmatic version of a tutorial than you will find at the official Google App Engine Website. You might want to refer to that link, again in the references section, if you want to refer to it for some of the items we cover, as it does a great job of covering things in great detail. This tutorial is really a "backwards first" tutorial, so if you have trouble understanding this tutorial, come back to it after you finish the official one. From here on out, any download or link mentioned will be available in the Resources section at the bottom.

Getting Started

There were approximately 10,000 beta accounts given out for Google App Engine, so if you didn't get lucky like me, you can still develop using the SDK offline, and then when it is opened up you will be already to go. First you will need to download the SDK, and then you only need to follow three steps to get a helloworld application working:

Step 1:

create a helloworld directory and create a file named helloworld.py inside of it:

    print 'Content-Type: text/plain'
    print ''
    print 'Hello, world!'

Step 2:

inside of helloworld create a file named app.yaml that looks like this:

    application: helloworld
    version: 1
    runtime: python
    api_version: 1

    handlers:
    - url: /.*
      script: helloworld.py

Step 3:

Next you just need to run the dev_appserver.py script by either giving the full path to your directory or just a "." if you are in the directory. This is how it looks for me when I run it from inside of the actual directory.

dev_appserver.py .

If you navigate to: http://localhost:8080/ you will see your hello world application in action. That is all there is to getting started with developing an application. As you will see in a bit, the API is incredibly powerful, so writing an application with GAE can be trivial.

Backwards First

Now that we have helloworld out of the way, let's crack open the source code for our instructional application and break it down. At this point you will need to check it out from subversion, and then change into the directory to run the sample code. Again to run the application you just need to type:

dev_appserver.py .

I would leave this running in a terminal window as it will automatically figure out when you make changes. In another window in your favorite text editor open up change.py. This one file does most of the work of our application, and here it is for posterity:

    #!/usr/bin/env python2.5
    #Noah Gift

    import decimal
    import wsgiref.handlers
    import os

    from google.appengine.api import users
    from google.appengine.ext import webapp
    from google.appengine.ext import db
    from google.appengine.ext.webapp import template

    class ChangeModel(db.Model):
        user = db.UserProperty()
        input = db.IntegerProperty()
        date = db.DateTimeProperty(auto_now_add=True)

    class MainPage(webapp.RequestHandler):
        """Main Page View"""

        def get(self):
            user = users.get_current_user()

            if users.get_current_user():
                url = users.create_logout_url(self.request.uri)
                url_linktext = 'Logout'
            else:
                url = users.create_login_url(self.request.uri)
                url_linktext = 'Login'

            template_values = {
            'url': url,
            'url_linktext': url_linktext,
            }
            path = os.path.join(os.path.dirname(__file__), 'index.html')
            self.response.out.write(template.render(path, template_values))

    class Recent(webapp.RequestHandler):
        """Query Last 10 Requests"""

        def get(self):

            #collection
            collection = []
            #grab last 10 records from datastore
            query = ChangeModel.all().order('-date')
            records = query.fetch(limit=10)

            #formats decimal correctly
            for change in records:
                collection.append(decimal.Decimal(change.input)/100)

            template_values = {
            'inputs': collection,
            'records': records,
            }

            path = os.path.join(os.path.dirname(__file__), 'query.html')
            self.response.out.write(template.render(path,template_values))

    class Result(webapp.RequestHandler):
        """Returns Page with Results"""
        def __init__(self):
            self.coins = [1,5,10,25]
            self.coin_lookup = {25: "quarters", 10: "dimes", 5: "nickels", 1: "pennies"}

        def get(self):
            #Just grab the latest post
            collection = {}

            #select the latest input from the datastore
            change = db.GqlQuery("SELECT * FROM ChangeModel ORDER BY date DESC LIMIT 1")
            for c in change:
                change_input = c.input

            #coin change logic
            coin = self.coins.pop()
            num, rem  = divmod(change_input, coin)
            if num:
                collection[self.coin_lookup[coin]] = num
            while rem > 0:
                coin = self.coins.pop()
                num, rem = divmod(rem, coin)
                if num:
                    collection[self.coin_lookup[coin]] = num

            template_values = {
            'collection': collection,
            'input': decimal.Decimal(change_input)/100,
            }

            #render template
            path = os.path.join(os.path.dirname(__file__), 'result.html')
            self.response.out.write(template.render(path, template_values))

    class Change(webapp.RequestHandler):

        def post(self):
            """Printing Method For Recursive Results and While Results"""
            model = ChangeModel()
            try:
                change_input = decimal.Decimal(self.request.get('content'))
                model.input = int(change_input*100)
                model.put()
                self.redirect('/result')
            except decimal.InvalidOperation:
                path = os.path.join(os.path.dirname(__file__), 'submit_error.html')
                self.response.out.write(template.render(path,None))

    def main():
        application = webapp.WSGIApplication([('/', MainPage),
                                            ('/submit_form', Change),
                                            ('/result', Result),
                                            ('/recent', Recent)],
                                            debug=True)
        wsgiref.handlers.CGIHandler().run(application)

    if __name__ == "__main__":
        main()

As a backwards first tutorial, lets start by looking at either the version running at http://greedycoin.appspot.com, or your development version at http://localhost:8080/. There is a pumpkin colored theme that has two floating boxes, on the left is a form that lets you input change, and on the right there is a navigation box. These pretty, or ugly, colors, and layout are just a combination of django templating and CSS. The django templates can be found in the main directory, and the css I used is found in stylesheets. This really has little to do with Google App Engine, so I will just refer you to Django templating reference material if you are not familiar with them.

Now that we have covered this, let's actually get into some Google App Engine specifics. If you notice the "Login" link in the right navigation box, it is made possible by the clever user authentication API. Here is what that actual code looks like:

    class MainPage(webapp.RequestHandler):
        """Main Page View"""

        def get(self):
            user = users.get_current_user()

            if users.get_current_user():
                url = users.create_logout_url(self.request.uri)
                url_linktext = 'Logout'
            else:
                url = users.create_login_url(self.request.uri)
                url_linktext = 'Login'

            template_values = {
            'url': url,
            'url_linktext': url_linktext,
            }
            path = os.path.join(os.path.dirname(__file__), 'index.html')
            self.response.out.write(template.render(path, template_values))

There is a class that inherits from webapp.RequestHandler and if you define a get method you can make a page that checks to see if a user is logged in or not. If you notice the few lines at the bottom, you will see that the user information gets tossed into the template system and then gets rendered to the Django template file index.html. What is incredibly powerful, is that it is trivial to leverage the Google User Accounts database to create authorization for pages. If you look at the code above it is as simple as saying:

    user = users.get_current_user()

            if users.get_current_user():

I would suggest fiddling around with this code and trying to add code that only shows up for authenticated users. You don't even need to understand how things work, you could just use the existing conditional statements to do something.

Datastore Backwards First

Now that we a vague understanding about authentication, lets get into the powerful stuff. The Datastore API lets you store persistent data and then retrieve it throughout your application. In order to do this you need to import the datastore, as shown in the above code, and then also define a model like this:


    class ChangeModel(db.Model):
         user = db.UserProperty()
        input = db.IntegerProperty()
         date = db.DateTimeProperty(auto_now_add=True)

With that simple class we can now create and use persistent data. Here is a class in which I use Python API to the Datastore to retrieve the last 10 changes made to the database, and then display them:

    class Recent(webapp.RequestHandler):
         """Query Last 10 Requests"""

                 def get(self):

                 #collection
                 collection = []
                 #grab last 10 records from datastore
                 query = ChangeModel.all().order('-date')
                 records = query.fetch(limit=10)

                 #formats decimal correctly
                 for change in records:
                     collection.append(decimal.Decimal(change.input)/100)

                template_values = {
                 'inputs': collection,
                 'records': records,
                 }

                 path = os.path.join(os.path.dirname(__file__), 'query.html')
                 self.response.out.write(template.render(path,template_values))

The two most important lines are:

    query = ChangeModel.all().order('-date')
    records = query.fetch(limit=10)

These pull the results out of the Datastore and then "fetch" 10 records in a query At this point, a simple thing to do for fun, would be to experiment with with this code and to try to fetch more records, or to sort them in a different way. This should give you some immediate and fun feedback.

URLS Backwards First

Believe it or not, we are about done with our reverse tutorial. The last bit of code to look at is the main function: Looking closely you might be able to guess that each of the URLs corresponds to a class we defined in our change.py file. At this point, I would recommend trying to tweak the names of URLS by changing the parts of the application that depend on a URL, this will give you a good idea of how things get routed around.

ADDITIONAL APP ENGINE INFORMATION

Python Web Frameworks, Google App Engine, and Webob

One of the more interesting aspects of Google App Engine is the inclusion of a very simple WSGI-compatible web application framework called webapp. A large and critical portion of this framework is based on a slightly modified version of Webob, a third party library created by Ian Bicking. Webob "provides objects for HTTP requests and responses", and has been under constant development by Ian over the last few years. As a side note, the Pylons web framework uses Webob as well. One slight modification that occurred with Webob is that the actual Response object was replaced with a custom Response object within the GAE webapp framework.

While the default web framework is a hybrid creation that Google engineered, it is also possible to run some of the popular Python frameworks, such as Pylons, web.py, and Django. There is also some talk of getting Zope 3 and Grok to work on GAE this summer, and this may develop at the upcoming Google I/O event. In addition, although Django templates are included, it is also possible to run a very popular fork of Django templates called, Jinja, as well as Mako and possibly a development version of Genshi. Please see the resource section for links to some of the projects, and special hacks.

Google I/O Event

If this tutorial got you interested in writing the next MySpace or Facebook with Google App Engine, then you might want to consider attending the Google I/O Event. I will be attending the Google I/O Event on May 28th and 29th in San Francisco, and am very excited to go. I was fortunate enough to score a phone interview with Tom Stocky, who is a Senior Product Manager at Google, and he had this to say about the Google I/O event.

"Google I/O is for developers interested in being part of the next

generation of web apps," said Tom Stocky, senior product manager at

Google. "It's the one time this year that we'll have the engineering

teams working on developer products all in one place, engaged with the

community."

SUMMARY

This article glossed over quite a few of the details of making a basic application, so if you feel it went too fast, then make sure you go through the complete official tutorial. Once you get done with that, come back to this code and take a look again to get some ideas, or just steal the fancy "pumpkin" CSS.

At this point in the article I get to give my opinion of the Google App Engine. I would rate it a 9.5 on a scale of 1-10. The environment just fits my brain, and I have no problem with developing complex applications with exactly the tools I was given. It might be nice to get a few more options for templating, and such, but it was a slam dunk for me. In fact I am so excited about building App Engine applications, I might need to hide my expresso machine for a bit. Feel free to contact me with questions, or hopefully consulting offers to work on a crazy App Engine project.

REFERENCES

Live Greedy Coin Tutorial Application
Source Code via SVN
Google App Engine Getting Started Guide
App Engine SDK Download
Django Templates
Webob
appengine-monkey
Do-It-Yourself
Webapp
Ian Bicking Home Page
Pylons Web Framework
Jinja templates
Mako templates

Noah Gift is the co-author of Python For Unix and Linux by O'Reilly. He is an author, speaker, consultant, and community leader, writing for publications such as IBM Developerworks, Red Hat Magazine, O'Reilly, and MacTech, and Manning.


Return to ONLamp.com.

Copyright © 2009 O'Reilly Media, Inc.