This document discusses building modern mobile/web applications using a "triple crown" approach of mobile, web and cloud technologies. It promotes using Google Cloud Endpoints to build RESTful APIs, deploying applications to Google App Engine, and using AngularJS for client-side development. The document provides an example of building a photo sharing application with CRUD operations using these techniques. It demonstrates enhancing the application with features like offline support, authentication and updating the API based on client needs.
4. AngularJS - Client Side Framework
Angular.js - Let you extend HTML
vocabulary for your application.
● Data binding
● Extensible HTML
● Dependency Injection / Testable
#io13
More options: addyosmani.github.com/todomvc/
5. Mobile World - RESTful World
#io13
Photos
● GET http://ex.com/_ah/api/picturesque/v1/photos
● POST http://ex.com/_ah/api/picturesque/v1/photo
● PATCH http://ex.com/_ah/api/picturesque/v1/photo/id
Users
● POST http://ex.com/_ah/api/picturesque/v1/users/join
And more...
6. ● Performance! #Perfmatters
● Flaky connections (e.g. cafes, car)
● Airplane, road trip, deserted island
● Consolidates the concept of permanent application.
* We will use: Lawnchair for our demo.
Offline - Why?
#io13
7. ● Storing assets: AppCache
● Storing data: localStorage, IndexedDB, File API.
● Offline first:
○ Pretend that there's no internet connection
○ Implement a sync layer that works only when
online.
Offline - How?
navigator.onLine & window.(ononline|onoffline)
#io13
9. Modern Apps and The Server Conundrum
All modern applications have to deal with a server
○ Offload Computation
○ Sharing and Collaboration
○ Logs
But who wants to run a server
○ Spikey traffic
○ Client Server communication
○ Serialization
○ OAuth Dance
#io13
19. Data Model for CRUD App
Python
from endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel):
...
20. Data Model for CRUD App
Python
from endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel):
title = ndb.StringProperty()
21. Data Model for CRUD App
Python
from endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel):
title = ndb.StringProperty()
description = ndb.StringProperty()
22. Data Model for CRUD App
Python
from endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel):
title = ndb.StringProperty()
description = ndb.StringProperty()
base64_photo = ndb.BlobProperty('base64Photo', indexed=False)
23. Data Model for CRUD App
Python
from endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel):
title = ndb.StringProperty()
description = ndb.StringProperty()
base64_photo = ndb.BlobProperty('base64Photo', indexed=False)
updated = ndb.DateTimeProperty(auto_now=True, indexed=False)
24. Data Model for CRUD App
Python
from endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel):
_message_fields_schema = ('id', 'title', 'description',
'base64Photo', 'updated')
title = ndb.StringProperty()
description = ndb.StringProperty()
base64_photo = ndb.BlobProperty('base64Photo', indexed=False)
updated = ndb.DateTimeProperty(auto_now=True, indexed=False)
26. Using Data Model for Insert
Python
@endpoints.api(name='picturesque', version='v1',
description='Photos API for Picturesque App')
class PicturesqueApi(remote.Service):
@Photo.method(path='photo', name='photo.insert')
def PhotoInsert(self, photo):
# do some validation
photo.put()
return photo
30. Add some tags to support that UI
Python
class Photo(EndpointsModel):
title = ndb.StringProperty()
description = ndb.StringProperty()
base64_photo = ndb.BlobProperty('base64Photo', indexed=False)
created = ndb.DateTimeProperty(auto_now_add=True, indexed=False)
tags = ndb.StringProperty(repeated=True)
31. List and Search, All at Once
Python
@Photo.query_method(query_fields=('limit', 'pageToken', 'title'),
path='photos', name='photo.list')
def PhotoList(self, query):
return query
32. List Demo - Get Photos Baby!
Python
var req = gapi.client.picturesque.photo.list();
req.execute(function(data) {
data.items = data.items || [];
console.log("-- We have " + data.items.length);
addPhotos(data.items);
});
37. Interface Informed by Client
● Network calls are expensive
● "Client" photo library
○ Lawnchair allows us to store photos' metadata offline
○ filer.js to store the photos
○ Application Cache
○ HTML5 Storage
● DRY: Applies to code and to API calls
○ Only retrieve photos that have been updated since the last
API call
38. Extending query_method
Python
from endpoints_proto_datastore.ndb import EndpointsAliasProperty
from endpoints_proto_datastore import utils
class Photo(EndpointsModel):
...
_last_updated = None
@EndpointsAliasProperty(name='lastUpdated', setter=LastUpdatedSet)
def last_updated(self):
if self._last_updated is not None:
try:
return utils.DatetimeValueToString(self._last_updated)
except:
raise endpoints.BadRequestException(
'Invalid timestamp for lastUpdated')
39. Extending query_method
Python
class Photo(EndpointsModel):
...
def LastUpdatedSet(self, value):
try:
self._last_updated = utils.DatetimeValueFromString(value)
if not isinstance(self._last_updated, datetime.datetime):
self._last_updated = None
raise TypeError('Not a datetime stamp.')
except TypeError:
raise endpoints.BadRequestException('Invalid timestamp for lastUpdated.')
self._endpoints_query_info._filters.add(
Photo.updated >= self._last_updated)
42. Key Take Aways
● Build powerful applications with Google Cloud Endpoints
● Cloud Endpoints makes for easy deployment at scale
● Use AngularJS to be more productive
● Leverage Modern Browser Features:
○ Offline
○ Web RTC
○ Websockets
○ New CSS3 artifacts
○ Web workers
#io13