00:00:00

Daybed

spatial storage as a service !

media/front-rest-daybed.png

Notes

  • Mathieu Leplatre (@leplatrem)
  • PostGIS and Leaflet enthusiast (training, plugins, Django apps)
  • JavaScript and Python dev (freshman at Mozilla)

http://leplatrem.github.io/slides/201501-fosdem/

Notes

How would you build... ?

Notes

Usually, you implement and deploy a backend...

media/no-dev-backend-1.png

Notes

With Daybed, you just plug your app !

media/no-dev-backend-2.png

Notes

Why Daybed ?

  • Build collaborative apps
    (basic, spatial, encrypted, ...)
  • Build a Google Forms alternative
    (form → model, submission → record)
  • Do not reinvent the wheel
    (JavaScript app without API dev)
  • Prototype Web applications
    (Frontend-dev only)

Notes

Daybed is not...

  • Another DBMS (too naive)
  • A framework (client agnostic)
  • The golden hammer (not everything is a nail)
  • A company with a business plan

Notes

Daybed is...

Notes

A simple REST API... for any HTTP client!

media/daybed-archi.png
  • Open source (BSD)

Notes

That you deploy once!

media/deploy-once.png

Notes

And use intuitively...

media/daybed-steps.png

Notes

Under the hood

  • Pyramid, a robust and powerful python Web framework
  • Cornice, a REST framework for Pyramid
  • Colander for the schema validation part
  • Redis as the default persistence backend
    (or CouchDB)
  • ElasticSearch as indexing and faceted search engine (pluggable)

Notes

Key features

  • Record validation (from model schema)
  • Authentication (Hawk tokens)
  • Permissions (CRUD, by author etc.)
  • Simple model relations

Notes

Spatial features

  • Geometries field types
    (point, lines, polygons, geojson...)
  • GeoJSON content type (feature collection)
  • Spatial indexing (bounding box, distance, ...)

Notes

Model definition

  • Model id
  • List of fields (int, string, relations, ...)
  • List of permissions

→ REST endpoints /models/<id>/definition
/models/<id>/records

Notes

Permissions

  • Creator of model has full permissions

Optional matrix, by model:

  • userid, anonymous, authenticated
  • create, read (all|own), update (all|own) delete (all|own)
  • (read|modify|delete) model definition

Notes

Daybed.js

  • Wrap HTTP requests
  • Bring promises (with polyfill)
  • Authentication tokens (Hawk signing)
  • Helpers for sharing/syncing
<script src="//js.daybed.io/build/daybed.js"></script>

Notes

Getting started

var definition = {
  title: 'FOSDEM',
  description: 'Simple locations',
  fields : [
    {name: 'location', type: 'point'},
    {name: 'label', type: 'string'},
  ]
};

var permissions = {
  'Everyone': ['create_record', 'read_all_records',
               'update_all_records', 'delete_all_records']
};

Notes

Getting started

var model = {
  definition: definition,
  permissions: permissions
};

var server = 'https://daybed.io';
var modelId = 'a-simple-location-model-with-label';

Daybed.startSession(server)
  .then(function (session) {
    return session.saveModel(modelId, model);
  });

Notes

Load records

  • Default format is JSON
  • GeoJSON feature collection renderer
    (Accept header)
var session = new Daybed.Session(server);

session.getRecords(modelId, {
    format: 'application/vnd.geo+json',
  })
  .then(function (geojson) {
    L.geoJson(geojson).addTo(map);
  });

Notes

Create records

  • POST data
  • Validated against model schema
  • Obtain record id
map.on('dblclick', function(e) {
  // LatLng to [x, y]
  var point = [e.latlng.lng, e.latlng.lat];

  session.saveRecord(modelId, {
      label: 'Building',
      location: point
    })
    .then(function(record) {
      var layer = L.marker(e.latlng).addTo(map);
      // Keep record id
      layer._recordId = record.id;
    });
});

Notes

Modify and delete

  • For example, delete on marker click:
layer.on('click', function () {
  // Using record id
  session.deleteRecord(model, layer._recordId)
    .then(function () {
      map.removeLayer(layer);
    });
});
  • RESTful verbs (PUT, PATCH, DELETE)
  • session.deleteRecord(modelId, id)
    session.saveRecord(modelId, record)

Notes

Share authentication token

  • Shared token → collaborative app!

For example, via URL hash:

var token = window.location.hash.slice(1);

Daybed.startSession(server, {token: token})
  .then(function (session) {
    window.location.hash = session.token;
  })
  .catch(function (e) {
    console.error("Could not start session", e);
  });
media/location-token.png

Notes

Lookup records

  • E/S mappings are generated from model definitions
  • Records are indexed on creation
  • Every basic geometric types
  • Operators on BBox, distance
  • Geo point aggregates (a.k.a. clustering) via plugin

The best Web companion !

  • Sorts, paginates, aggregates, counts
  • Scales — Insanely fast — Ubiquitous

Notes

Bounding box search

  • Build queries in JSON !
var query = {
  ...
    filter: { geo_bounding_box : {
        location: {
          top: bbox.getNorthWest().lat, left: bbox.getNorthWest().lng,
          bottom: bbox.getSouthEast().lat, right: bbox.getSouthEast().lng
        }
      } }
  ...
};

session.searchRecords(modelId, query)
  .then(function (response) {
    alert(response.hits.hits.length + ' results!');
  });

Notes

Conclusion

Notes

Generic API means...

  • No effort on backend (quick start)
  • Logic-less API (very basic rules)
  • Easier with schemaless database
    (...or PostgreSQL json!)
  • More work on the client (computation, conflicts)

→ Daybed on server + Turf.js on client ?

Notes

About your use-case ?

  • Deploy one backend! Roll out many applications!

→ Think twice before implementing a custom backend!

http://daybed.rtfd.orghttps://daybed.io/v1/

Notes

Some ideas...

  • Form builder
  • Websockets / SimplePush
  • Precondition headers
  • A bit more HATEOAS

See also

  • postgrest (PostgreSQL as API, Haskell)
  • Eve (build generic APIs, Python)

Notes