Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Offline-First Apps with PouchDB at ConFoo

Bradley Holt
February 25, 2016

Offline-First Apps with PouchDB at ConFoo

Web and mobile apps shouldn't stop working when there's no network connection. Based on Apache CouchDB, PouchDB is an open source syncing JavaScript database that runs within a web browser. Offline-first apps built using PouchDB can provide a better, faster user experience—both offline and online. Learn how to use the HTML5 Offline Application Cache, PouchDB, and CouchDB to build offline-enabled web and mobile apps.

Bradley Holt

February 25, 2016
Tweet

More Decks by Bradley Holt

Other Decks in Programming

Transcript

  1. ConFoo 2016 Bradley Holt, Developer Advocate Thursday, February 25, 2016

    Offline-First Apps with PouchDB @BradleyHolt
  2. Why offline first?

  3. None
  4. None
  5. Mobile First Design for the smallest device first and then

    apply progressive enhancement techniques to take advantage of larger screen sizes
  6. Offline First Design for offline usage first and then apply

    progressive enhancement techniques to take advantage of network connectivity when available
  7. Ubiquitous Connectivity Why offline first in a world of ubiquitous

    connectivity?
  8. 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
  9. Mobile Backend What happens when your mobile backend service is

    unreachable?
  10. Benefits of Offline First

  11. Faster User Experience Better, faster user experience — both offline

    and online
  12. Works Offline Ability to disconnect and continue to work offline

  13. Battery and Bandwidth Limited access to power and communications infrastructure

    in disaster scenarios
  14. Offline-First Patterns and Anti-Patterns

  15. None
  16. None
  17. None
  18. None
  19. None
  20. Tools and Use Cases

  21. CouchDB Replication Protocol @BradleyHolt Cloudant Sync IBM Cloudant DBaaS CouchDB

    PouchDB CouchDB Replication Protocol
  22. @BradleyHolt

  23. PouchDB Code Examples

  24. None
  25. IBM Cloudant §  Globally distributed data layer for web and

    mobile applications §  MongoDB-style queries §  Advanced geospatial capabilities §  Full text search indexing @BradleyHolt
  26. 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
  27. Creating a Local PouchDB Database var db = new PouchDB("smart-meter");

    @BradleyHolt
  28. Creating a Remote PouchDB Database var remoteDb = new PouchDB("https://bradley-holt.cloudant.com/smart-meter");

    @BradleyHolt
  29. Cross-Origin Resource Sharing (CORS) §  Enable Cross-Origin Resource Sharing (CORS)

    on remote database §  Browsers place security restrictions on cross-site HTTP requests §  If you run into a problem, remember this warning! @BradleyHolt
  30. 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
  31. 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
  32. Deleting a Document db.put({ _id: "2014-11-12T23:27:03.794Z", kilowatt_hours: 14 }).then(function(response) {

    // Get the document return db.get(response.id); }).then(function(doc) { // Remove the document from the database return db.remove(doc); }).catch(function(error) { console.log(error); }); @BradleyHolt
  33. 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
  34. allDocs Options §  include_docs – conflicts – attachments §  startkey §  endkey

    §  inclusive_end (true by default) §  limit §  skip §  descending §  key §  keys @BradleyHolt
  35. 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
  36. Querying a Database with PouchDB Find §  Based on Cloudant

    Query, aka Mango §  MongoDB-style query language §  Define fields to index @BradleyHolt
  37. Replication Patterns

  38. One Database Per User @BradleyHolt Clemmie Danyel Shelba Manuel Francis

    Marissa Mitchel Georgianne Garnet Audrey Kalyn
  39. Write-Only Replication §  Data generated on the device §  Replicate

    this data to the cloud from multiple users and/or devices §  Example uses: –  User updates –  Sensor data @BradleyHolt
  40. Write-Only Replication var db = new PouchDB("smart-meter"); var remoteDb =

    new PouchDB( "https://bradley-holt.cloudant.com/smart-meter" ); @BradleyHolt
  41. Write-Only Replication 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) { … }).catch(function(error) { console.log(error); }); @BradleyHolt
  42. Write-Only Replication db.replicate.to(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
  43. Read-Only Replication §  Data generated in the cloud §  Replicate

    this data to multiple users and/or devices from the cloud §  Example uses: –  Weather –  Notifications @BradleyHolt
  44. Read-Only Replication remoteDb.replicate.to(db, { 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
  45. Bidirectional Replication §  Data generated on both the device and

    in the cloud §  Replicate this data to/from the cloud and to/from multiple users and/or devices §  Useful when you need to share data between users and/or devices @BradleyHolt
  46. 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
  47. 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
  48. Filtered Replication §  Select (with a function) which documents to

    replicate §  Filter can be defined locally within PouchDB, or remotely on Cloudant @BradleyHolt
  49. 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
  50. None
  51. 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
  52. Cloudant FoodTracker

  53. None
  54. 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> §  Grunge Warning Sign - Do Not Read This Sign by Nicolas Raymond, on Flickr <https://flic.kr/p/cirSCd> §  Mango with section on a white background by bangdoll, on Flickr <https://flic.kr/p/9CBP2h> @BradleyHolt
  55. Questions? @BradleyHolt