Follow Along!

App Engine Overview

What is Google App Engine?

Easy to build

Easy to scale

Easy to maintain

Google App Engine

Easy to build



Storage



Datastore, Cloud SQL,
Memcache


Compute



Frontends, Backends,
Task Queues, Cron


Services



Users, Mail, Images,
UrlFetch, MapReduce,
TrafficSplitting, Search

Easy to scale

QPS diagram

0 to 23K QPS

Easy to maintain

At other companies I’ve been with, there was always a need to be on call after hours to deal with server problems. This isn’t necessary here, because Google App Engine just works.
Stefan Hauk
Lead server developer for web games, Rovio

Some stats

1,000,000 active applications

2 trillion datastore operations per month

half of active world IP addresses touch App Engine each week

Mobile Backends with App Engine

How it used to work

  • Buy a server and put it in your basement
  • Install your stack
  • Add or build services you need. Chat? Mail? Search?
  • Write an API. Authorization? Authentication? Wire format? Compression?
  • Build wrappers for each for you clients. JS? Java? Objective-C?
  • Launch your app and start over because it doesn't scale
  • Realize that what you're actually spending time on is not building your application

Enter Google Cloud Endpoints

Endpoints Architecture

Endpoints Features

  • Support for Java and Python backends
  • Built on Google's API infrastructure
  • JSON wire format with automatic GZip
  • Automatically-generated, statically-typed client libraries for Android and iOS
  • Dynamically-typed JS client library
  • Built in support for OAuth 2
  • Integration with the Google Plugin for Eclipse
  • Support for local development

Endpoints: How does it work?

Write your backend code

public class Game {
  public Game updateGame(String state) {
    // method logic here
    return game;
  }
}

Endpoints: How does it work?

Annotate API methods

@Api
public class Game {
  public Game updateGame(@Named("state") String state) {
    // method logic here
    return game;
  }
}

Endpoints: How does it work?

Generate client libraries

localhost:home user$ ./ServiceGenerator my-api-v1-rpc.discovery
==========================================================
Writing:
 + GTLQueryMyApi.h (1610 bytes) - NEW
 + GTLQueryMyApi.m (2316 bytes) - NEW
 + GTLServiceMyApi.h (1471 bytes) - NEW
 + GTLServiceMyApi.m (1364 bytes) - NEW
 + GTLMyApi.h (474 bytes) - NEW

Endpoints: How does it work?

Write client applications

GTLGame *game = [GTLGame alloc];
[game setState:state];
GTLQueryGame *query = [GTLQueryGame queryForGameUpdateWithObject:game];
...

Demo!

Tic Tac Toe

Try it out!

Adding Auth

Adding Auth

Updating the backend: part 1

@Api(
    name = "tictactoe",
    version = "v1",
    clientIds = {Ids.WEB_CLIENT_ID, Ids.ANDROID_CLIENT_ID, Ids.IOS_CLIENT_ID},
    audiences = {Ids.ANDROID_AUDIENCE}
)
public class Ids {
  public static final String WEB_CLIENT_ID = "abc123.apps.googleusercontent.com";
  public static final String ANDROID_CLIENT_ID = "abc123-4567.apps.googleusercontent.com";
  public static final String IOS_CLIENT_ID = "abc123.apps.googleusercontent.com";
  public static final String ANDROID_AUDIENCE = WEB_CLIENT_ID;
}

Adding Auth

Updating the backend: part 2

@ApiMethod(name = "scores.insert")
public Score insert(Score score, User user) throws
    OAuthRequestException, IOException {
  if (user != null) {
    score.setPlayed(new Date());
    score.setPlayer(user);
    PersistenceManager pm = getPersistenceManager();
    pm.makePersistent(score);
    pm.close();
    return score;
  } else {
    throw new OAuthRequestException("Invalid user.");
  }
}

Adding Auth

Updating JS: initialization

var apisToLoad = 2;
var callback = function() {
  if (--apisToLoad == 0) {
  signin(true, userAuthed);
  }
}
gapi.client.load('tictactoe', 'v1', callback, apiRoot);
gapi.client.load('oauth2', 'v2', callback);

Adding Auth

Updating JS: attempt sign-in

function signin(mode, callback) {
  gapi.auth.authorize({client_id: CLIENT_ID,
    scope: SCOPES, immediate: mode,
    response_type: 'token id_token'},
    callback);
}

Adding Auth

Updating JS: auth callback

function userAuthed() {
  var request =
      gapi.client.oauth2.userinfo.get().execute(function(resp) {
    if (!resp.code) {
      var token = gapi.auth.getToken();
      token.access_token = token.id_token;
      gapi.auth.setToken(token);
      // User is signed in, call Endpoints
    }
  });
}

Adding Auth

Updating JS: update the UI

<a href="#" onclick="auth();" id="signinButton">Sign in!</a>

This calls authorize without immediate mode:

function auth() {
  signin(false, userAuthed);
}

Tic Tac Toe

Once more…with authentication!

Further Reading

Thank You!