What is Google App Engine?

Google App Engine is a complete development stack that uses familiar technologies to build and host applications on the same infrastructure used at Google.

Four runtime environments


Python


Java


Go


PHP

Your code runs in a sandbox

http://www.flickr.com/photos/damongman/5623130732/

The Sandbox

Secure environment that provides limited access to the underlying operating system.

The sandbox allows App Engine to

  • distribute web requests across multiple servers
  • start and stop servers to meet traffic demands
  • isolate apps in a secure, reliable environment
  • abstract hardware, operating system and physical location of the web server

Sandbox limitations

  • outbound connections: only through the provided URL fetch and email services or the experimental Socket API.
  • inbound connections: only HTTP(s) on ports 80/443.
  • filesystem access: writing files is not allowed. An application can read only files uploaded with the application code.
  • no native code: libraries that depend on native code are generally not available.
  • time limits: app code must terminate within given time limits. (60s for web requests, 10m for tasks but unlimited time for backend jobs)

Storing data

Three options for data storage

App Engine Datastore a NoSQL schemaless data storage built in GAE

Google Cloud SQL a relational SQL database service based on MySQL

Google Cloud Storage file based storage

No fixed costs: pay only for what you use...

http://www.flickr.com/photos/jasonalley/5039425430

...with generous free quotas

http://www.flickr.com/photos/toddle_email_newsletters/7002322316

Getting app & running

See it in action

Download the SDK

Start up the launcher

App Engine Launcher Screenshot

Create a sample application

Creating a new app with the Launcher

Run!

http://www.flickr.com/photos/nihonbunka/46324600

Let's dive into code

Basics of the Python Runtime

Application Configuration

All configuration settings are stored in a file called app.yml

application: example
version: 1
runtime: python27
api_version: 1
threadsafe: yes

handlers:
- url: .*
  script: main.app

libraries:
- name: webapp2
  version: "2.5.2"

A self sufficient web application

App Engine supports webapp2 by default:

import webapp2

class MainHandler(webapp2.RequestHandler):
  def get(self):
    name = self.request.get('name')
    self.response.write('Hello %s!' % name)

app = webapp2.WSGIApplication([
    ('/', MainHandler)
], debug=True)

In addition to webapp2, the environment includes WebOb and Django.

Datastore(s)

  • There are two implementations of datastore
  • The original one is implemented in google.appengine.ext.db
  • The new one is called NDB and it is implemented in google.appengine.ext.ndb
  • They are very similar but not identical
  • We will cover NDB

Datastore

Creating an entity type is as easy as creating a Python class.

from google.appengine.ext import ndb

class Contact(ndb.Model):
  name = ndb.StringProperty()
  email = ndb.StringProperty()
  birth_date = ndb.DateProperty()

Querying the Datastore

The Datastore API is Object Oriented.

from google.appengine.ext import ndb

def StoresByCity(city, limit):
  query = Store.query(Store.city == city).order(Store.name)
  return query.fetch(limit, projection=[Store.name, Store.address])

Querying the Datastore with GQL

You can write queries with GQL, a SQL-like language.

from google.appengine.ext import ndb

qry = ndb.gql("SELECT * FROM Account WHERE balance < :1", 100)

GQL is translated to NDB's native query API. (This is the opposite of what traditional ORM libraries do!)

View templates

If you use webapp2, Django templates are supported by default.

<html>
  <body>
    {% for contact in contacts %}
      {% if contact.name %}
        <b>{{ contact.name }}</b>
      {% else %}
        Unnamed contact
      {% endif %}
      <{{ contact.email }}>
    {% endfor %}

    <a href="{{ url }}">{{ url_linktext }}</a>
  </body>
</html>

Alternatively, App Engine ships with jinja2, too.

Dispatch to view templates

Here is how to render a template in with webapp2:

def render_template(self, view_filename, params=None):
  if not params:
    params = {}
  path = os.path.join(os.path.dirname(__file__), 'views', view_filename)
  self.response.out.write(template.render(path, params))

Memcache

Memcache is a high-performance, distributed memory object caching system.

from google.appengine.api import memcache

def get_data():
  data = memcache.get('key')
  if data is not None:
    return data
  else:
    data = self.query_for_data()
    memcache.add('key', data, 60)
    return data

Can be used to minimize hits to the Datastore or to save transient state information.

Hands-on exercises

You will have to do some work now ;)

Preparation

  • Download the boilerplate code from here
  • Uncompress it
  • Open it up in a text editor/IDE you are familiar with
  • Take some time to familiarize with it

Exercise 1

(Quasi) Real Time Communication

Implement a backend for the page below

Channel Demo Screenshot

Your mission

  • Use the channel API to show the cursor position of every visitor's mouse.
  • Update the cursor position whenever users move their mouse.
  • Remove cursor icons when visitors leave the page.
  • Complete the code in the channel directory of the package you downloaded earlier and implement the missing methods.
  • Point your browser to http://localhost:$APP_PORT/channel to test your server.

Channel API

A channel connects two ends:

  • A client, which
    • connects to a channel,
    • listen for updates,
    • sends messages to the server.
  • A server, which
    • maintains a registry of open channels,
    • notifies clients of state changes.

The role of the Server

  • The server needs to keep track of the connected clients,
  • you can keep that information in memcache but
  • for this example, it is necessary to be notified of connections and disconnections.

There is a service for that! Enable presence in your app.yaml

inbound_services:
- channel_presence

and implement two handlers that can respond to POST at

  • /_ah/channel/connected/
  • /_ah/channel/disconnected/

Creating a Channel

Requires action on both ends. The server sends a token to the client:

def get(self):
  client_id = uuid.uuid4().hex
  token = channel.create_channel(client_id)
  template_values = {'client': client_id, 'token': token}
  self._render_template(template_values)

The client uses the token to create a channel

var client = "{{ client }}";
var channel = new goog.appengine.Channel('{{ token }}');
function setUpChannel() {
  var socket = channel.open();
  socket.onmessage = onMessage;
}

Using the Channel

The client can only read messages from the client.

function onMessage(message) {
  data = $.parseJSON(message.data);
  /* do something with data */
}

It can send data to the server via HTTP requests:

function sendCoordinates() {
  $.post('/channel', {
    x: current_x,
    y: current_y,
    client: client
  });
}

Exercise 2

Building an API Backend

Implement a backend for the page below

Cloud Endpoints Demo Screenshot

Your mission

  • Complete the code in the endpoints directory of the package you downloaded earlier and implement the missing methods.
  • Point your browser to http://localhost:$APP_PORT/endpoints to test your server.

Google Cloud Endpoints (experimental)

Google Cloud Endpoints consists of tools, libraries and capabilities that allow you to generate APIs and client libraries from an App Engine application.

Google Cloud Endpoints diagram

Create a service

Annotate the API implementation class with the endpoints decorators,

@endpoints.api(name='myapi', version='v1', description='My New API')
class MyNewApi(remote.Service):
  ...

create an API server instance,

application = endpoints.api_server([MyNewApi], restricted=False)

and map the instance to the API URL

handlers:
# Endpoints handler
- url: /_ah/spi/.*
  script: services.application

Define the API methods

Annotate methods with

@endpoints.method(RequestMessageClass,
                  ResponseMessageClass,
                  name='foo.bar',
                  path='/bar',
                  http_method='GET', ...)
def bar(self, request):
  ...
  • RequestMessageClass and ResponseMessageClass are ProtoRPC definitions of the request and response classes,
  • path is the URL path of the endpoint,
  • http_method allows to map different functions to different HTTP methods

Some closing notes on Endpoints

  • Apps that use Cloud Endpoints expose discovery services at https://your_app_id.appspot.com/_ah/api/discovery/v1/apis
  • You can also use the APIs Explorer to experiment with your API by visiting https://your_app_id.appspot.com/_ah/api/explorer
  • You can use the SDK to generate JavaScript, Android and iOS clients for your service,
  • Endpoints can authenticate clients using OAuth 2.0,
  • If you want to build a REST API, check out Endpoints Proto Datastore,
  • and if you work with Android applications, check out the Mobile Backend Starter.

There's more

A few more advanced APIs

  • XMPP – Integrate your app with Google Talk and Instant Message Clients.
  • Search (experimental) – Build indexes for fast search over sets of document (which can be any object your app manipulates. Supports full text search and distance-based geographical search out of the box.
  • Prospective Search (experimental) – Analyze a real-time feed of documents and be notified when anything matches one of your searches.

Take your app to the next level

http://www.flickr.com/photos/msimdottv/4339697089

Time for a Challenge

Using the Search API to build a map-based application

Advanced Search

  • Using the Search API, build a location aware system.
  • Search for all the points that are closer than 10km from my position.
  • Run a full text search on the items descriptions.

<Thank You!>