mobile, web and cloud - the triple crown of modern applications
TRANSCRIPT
Mobile, Web and Cloud - The Triple Crown of Modern Applications
Ido Green, Developer AdvocateDanny Hermes, Developer Programs Engineer
Modern Mobile/Web Applications
Modern Applications
● Self Contained
● "Offline First"
● MV* Frameworks
● Device Aware
● #Perfmatters
#io13
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/
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...
● 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
● 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
Google Cloud Endpoints
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
Google App Engine
#io13
Google App Engine
#io13
Google Cloud Endpoints
#io13
Back the Truck Up
#io13
Google APIs: The Discovery Document
#io13
Google APIs: Client Libraries Like Whoa!!● Web
○ JavaScript: google-api-javascript-client○ Node.js: google-api-nodejs-client○ Dart: google-api-dart-client
● Mobile○ Objective C: google-api-objectivec-client○ Java: google-api-java-client
● Server-side○ Ruby: google-api-ruby-client○ Python: google-api-python-client○ Go: google-api-go-client○ PHP: google-api-php-client○ .NET: google-api-dotnet-client○ GWT: gwt-google-apis#io13
Google APIs
Client Libraries Like Whoa!!HTML
<body> ... <script type="text/javascript"> function init() { gapi.client.load(‘urlshortener’, 'v1’, function() {}); } </script> <script src="https://apis.google.com/js/client.js?onload=init"></script></body>
What Was that Again: Google Cloud Endpoints
#io13
Demo Time!
picturesque-app.appspot.com
Data Model for CRUD App
Pythonfrom endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel): ...
Data Model for CRUD App
Pythonfrom endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel): title = ndb.StringProperty()
Data Model for CRUD App
Pythonfrom endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel): title = ndb.StringProperty() description = ndb.StringProperty()
Data Model for CRUD App
Pythonfrom endpoints_proto_datastore.ndb import EndpointsModel
class Photo(EndpointsModel): title = ndb.StringProperty() description = ndb.StringProperty() base64_photo = ndb.BlobProperty('base64Photo', indexed=False)
Data Model for CRUD App
Pythonfrom 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)
Data Model for CRUD App
Pythonfrom 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)
Simple GET API Request
Using Data Model for Insert
[email protected](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
Insert With Drag and Drop Demo
Python
Update
Python @Photo.method(path='photo/{id}', http_method='PUT', name='photo.update') def PhotoUpdate(self, photo): if not photo.from_datastore: raise endpoints.NotFoundException('Photo not found.') photo.put() return photo
Add some tags to support that UI
Pythonclass 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)
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
List Demo - Get Photos Baby!
Pythonvar req = gapi.client.picturesque.photo.list();req.execute(function(data) { data.items = data.items || []; console.log("-- We have " + data.items.length); addPhotos(data.items);});
Lemme, Lemme Upgrade U!
picturesque-app-upgrade.appspot.com
Adding auth via OAuth 2.0
Python @Photo.method(user_required=True, path='photo/{id}', http_method='PUT', name='photo.update') def PhotoUpdate(self, photo): ...
Really that easy
Adding auth via OAuth 2.0
Pythonfrom endpoints_proto_datastore.ndb import EndpointsUserProperty
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_add=True, indexed=False) owner = EndpointsUserProperty(required=True, raise_unauthorized=True)
Alternative: Using models for auth
OAuth2.0 Demo - 1
Python
The li
ve dem
o
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
Extending query_method
Pythonfrom endpoints_proto_datastore.ndb import EndpointsAliasPropertyfrom 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')
Extending query_method
Pythonclass 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)
Extending query_method
Python @Photo.query_method(query_fields=('limit', 'pageToken', 'title', 'lastUpdated'), path='photos', name='photo.list') def PhotoList(self, query): return query.order(Photo.updated)
Client Side Conventions
JavascriptPicturesqueApp.showCarousel = function() { if (!PicturesqueApp.localImagesAdded) { PicturesqueApp.populateCarouselFromLocalImages();
};
PicturesqueApp.applyLastUpdated(PicturesqueApp.listSinceUpdated);};
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
Questions?
Ido GreenDeveloper Relationshttp://plus.google.com/+greenido
App:: https://picturesque-app-upgrade.appspot.com/
Code: https://github.com/greenido/
Slides: https://picturesque-app-upgrade.appspot.com/slides
Danny HermesDeveloper Programs Engineerplus.google.com/+DannyHermes