Mobile, web and cloud - the triple crown of modern applications
- 1. Mobile, Web and Cloud -
The Triple Crown of Modern Applications
Ido Green, Developer Advocate
Danny Hermes, Developer Programs Engineer
- 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
- 15. 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
- 16. 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>
- 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);
});
- 34. 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
- 35. Adding auth via OAuth 2.0
Python
from 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
- 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