Offline-First Apps with PouchDB and IBM Cloudant Cloud Computing Expo Bradley Holt, Developer Advocate Wednesday, June 8, 2016 @BradleyHolt
@BradleyHolt
IBM Cloud Data Services Open for Data A comprehensive por.olio of open source data services
Why offline first?
Mobile First Design for the smallest device first and then apply progressive enhancement techniques to take advantage of larger screen sizes when available
Offline First Design for offline usage first and then apply progressive enhancement techniques to take advantage of network connectivity when available
Ubiquitous Connectivity Why offline first in a world of ubiquitous connectivity?
The Eight Fallacies of Distributed Computing 1. The network is reliable 2. Latency is zero 3. Bandwidth is infinite 4. The network is secure 5. Topology doesn't change 6. There is one administrator 7. Transport cost is zero 8. The network is homogeneous @BradleyHolt
Mobile Backend What happens when your mobile backend service is unreachable?
Benefits of Offline First
Faster User Experience Better, faster user experience both offline and online
Works Offline Ability to disconnect and continue to work offline
Battery and Bandwidth Limited access to power and communications infrastructure in disaster scenarios
Offline-First Patterns and Anti-Patterns
Tools and Use Cases
CouchDB Replication Protocol CouchDB CouchDB Replication Protocol CouchDB Cloudant Sync PouchDB @BradleyHolt
@BradleyHolt
PouchDB Code Examples github.com/bradley-holt/offline-first
JSON Documents { } _id: "6EF9D2B0-13D3-1378-8D30-39E3CE0B36C2", _rev: "1-0b457efcf82fb29492ef927ba5b6ee15", type: "Feature", geometry: { type: "Point", coordinates: [ -71.1028, 42.3691 ] }, properties: { session_id: "3486b13f-7b8a-8a96-dfbf-9b82800e367f", timestamp: 1422928591717 } @BradleyHolt
Creating a PouchDB Database var db = new PouchDB("smart-meter"); @BradleyHolt
Creating a New Document var db = new PouchDB("smart-meter"); db.put({ _id: "2014-11-12T23:27:03.794Z", kilowatt_hours: 14 }).then(function() { console.log("document created"); }).catch(function(error) { console.log(error); }); @BradleyHolt
Updating a Document db.put({ _id: "2014-11-12T23:27:03.794Z", kilowatt_hours: 14 }).then(function(response) { return db.get(response.id); }).then(function(doc) { // Update the value for kilowatt hours doc.kilowatt_hours = 15; // Put the document back to the database return db.put(doc); }).catch(function(error) { console.log(error); }); @BradleyHolt
Querying a Database with alldocs db.bulkdocs([ {_id: "2014-11-12T23:27:03.794Z", kilowatt_hours: 14}, {_id: "2014-11-13T00:52:01.471Z", kilowatt_hours: 15}, {_id: "2014-11-13T01:39:28.911Z", kilowatt_hours: 16}, {_id: "2014-11-13T02:52:01.471Z", kilowatt_hours: 17} ]).then(function(result) { // Get all documents return db.alldocs({include_docs: true}); }).then(function(response) { console.log(response); }).catch(function(error) { console.log(error); }); @BradleyHolt
alldocs Options include_docs conflicts attachments startkey endkey inclusive_end (true by default) limit skip descending key keys @BradleyHolt
Querying a Database with Map/Reduce Most queries can be done with alldocs (in PouchDB) Map functions transform documents into indexes Reduce functions aggregate results of Map functions _sum _count _stats @BradleyHolt
Querying a Database with PouchDB Find Based on Cloudant Query (Mango) Declarative indexes MongoDB-style query language @BradleyHolt
PouchDB Data Storage Limits Firefox Chrome Opera 15+ Internet Exporer 10+ ios Safari Safari (desktop) Android PhoneGap / Cordova Data Storage Limit 50MB (more with user permission) calculated calculated 250MB (prompts user at 10 MB) 50MB (prompts user at 5MB and at increments) unlimited (prompts user at 5MB and at increments) calculated / 200MB unlimited Adapter IndexedDB IndexedDB / WebSQL IndexedDB / WebSQL IndexedDB WebSQL WebSQL IndexedDB / WebSQL SQLite @BradleyHolt
Replication
Apache CouchDB CouchDB is a document database featuring an HTTP API, JSON documents, and peer-to-peer replication @BradleyHolt
Creating a Remote PouchDB Database var remotedb = new PouchDB("https://bradley-holt.cloudant.com/smart-meter"); @BradleyHolt
Cross-Origin Resource Sharing (CORS) A security restriction implemented by browsers on cross-site HTTP requests @BradleyHolt
Bidirectional Replication @BradleyHolt
Bidirectional Replication db.sync(remotedb, { live: false, retry: false }).on("change", function(info) { // Replication has written a new document console.log(info); }).on("complete", function(info) { // Replication has complete or been cancelled console.log(info); }).on("error", function(error) { // Replication has stopped due to an unrecoverable failure console.log(error); }); @BradleyHolt
Live Replication @BradleyHolt
Live Replication var sync = db.sync(remotedb, { live: true, retry: true }).on("change", function(info) { // Replication has written a new document console.log(info); }).on("complete", function(info) { // Replication has complete or been cancelled console.log(info); }).on("error", function(error) { // Replication has stopped due to an unrecoverable failure console.log(error); }); @BradleyHolt
Filtered Replication @BradleyHolt
Filtered Replication db.replicate.to(remotedb, { filter: function(doc) { return doc._id >= "2014-11-13T00:00:00.000Z"; } }).on("change", function(info) { // Replication has written a new document console.log(info); }).on("complete", function(info) { // Replication has complete or been cancelled console.log(info); }); @BradleyHolt
One Database Per User userdb-c082f2 userdb-85bcfe userdb-a1ec1f userdb-d76846 userdb-905cec userdb-adc95b userdb-730bba erdb-da3d25 userdb-9b9aba userdb-c3d3e5 userdb-85a327 @BradleyHolt
Boilerplates & Tools Frontend Web Apps React Boilerplate with Service Workers <https://github.com/mbrio/react-boilerplate/tree/react-0.13-flummox-service> Backend Web Apps PouchDB npm Package <https://www.npmjs.com/package/pouchdb> PouchDB Server npm Package <https://www.npmjs.com/package/pouchdb-server> Mobile Apps PouchDB for Ionic Framework <https://github.com/nolanlawson/pouchdb-ionic> "Hello world" Cordova app with PouchDB <https://github.com/nolanlawson/pouchdb-cordova-hello-world> "Hello world" Cordova app with PouchDB, using the SQLite Plugin <https://github.com/nolanlawson/pouchdb-cordova-hello-world-with-sqlite-plugin> Cloudant FoodTracker (uses Cloudant Sync for ios) <https://github.com/ibm-cds-labs/cloudant-food-tracker> Desktop Apps PouchDB for Electron (formerly Atom Shell) <https://github.com/nolanlawson/pouchdb-electron> PouchDB for Chrome packaged apps <https://github.com/nolanlawson/pouchdb-chrome-app> "Hello world" Chrome app with PouchDB <https://github.com/nolanlawson/pouchdb-chrome-app-hello-world> PouchDB for NW.js (aka Node-Webkit) <https://github.com/nolanlawson/pouchdb-nw> Internet of Things (IoT) Apps Node-RED <http://nodered.org/> @BradleyHolt
Cloudant FoodTracker An offline-first demo app built with Swift and Cloudant Sync for ios
Offline Camp June 24 th - 26 th, Catskill Mountains
offlinefirst.org/camp
Image Credits A mockup of the golden Apple iphone 5S by Zach Vega, on Wikimedia Commons <https://commons.wikimedia.org/wiki/file:iphone_5s.png> Joan Touzet (@wohali), ASF Member, CouchDB PMC Member <https://twitter.com/wohali/status/595689720933445632> Device landscape by Jeremy Keith, on Flickr <https://flic.kr/p/anlchu> Cloud Formation Over the Adirondacks by Bradley Holt, on Twitter <https://twitter.com/bradleyholt/status/623030107679002624> Cell phone tower by Gary Lerude, on Flickr <https://flic.kr/p/crl7tn> Pneumatic Central by Sleestak, on Flickr <https://flic.kr/p/mrvrq> Colunas by Daniel Zanini H., on Flickr <https://flic.kr/p/5zwhwv> Speed DLR on Doklands by Umberto Rotundo, on Flickr <https://flic.kr/p/7gmcuo> Waterfall by Paulo Valdivieso, on Flickr <https://flic.kr/p/onkvrp> Wildfire by U.S. Fish and Wildlife Service Southeast Region, on Flickr <https://flic.kr/p/8zkwgd> Arduino Uno by Pete Prodoehl, on Flickr <https://flic.kr/p/a3ky7e> Mango with section on a white background by bangdoll, on Flickr <https://flic.kr/p/9cbp2h> Warning by Stefano Brivio, on Flickr <https://flic.kr/p/tubha> @BradleyHolt
Questions? @BradleyHolt