Une solution de stockage

libre, générique et réutilisable

Il était une fois

Alice

Elle conçoit des applications

Elle a plein d'idées

Genre, vraiment

Du coup elle fait plein d'applis :)

Et la même question revient à chaque fois...

Où et comment je stocke les données ?

Comment je les synchronise ?

Du coup, à chaque fois...

<?php

class NewNewServer extends AbstractServerFactory {
  // mais pourquoi...
}

Alors elle se dit...

je vais utiliser un silo

Mais se posent alors d'autres questions...

  • Est-ce que le silo lit les données de mon application, de ses utilisateurs ?
  • Ils font quoi avec ?
  • Peuvent-ils me censurer, les censurer ?
  • Et niveau surveillance ?
  • Et si le service ferme ?

Kinto tente d'apporter une solution générique à l'ensemble de ces problèmes

Généricité

Généricité

  • HTTP
  • JSON
  • REST

Des concepts

et une API simples

/buckets

/buckets/todoapp

/buckets/todoapp/collections

/buckets/todoapp/collections/tasks

/buckets/todoapp/collections/tasks/records

/buckets/todoapp/collections/tasks/records/42

bucket / collection / record

$ http -a alice: :8888/v1/buckets
HTTP/1.1 200 OK
Total-Records: 0

{
    "data": []
}

Lister les buckets

$ http -a alice: PUT :8888/v1/buckets/todoapp
HTTP/1.1 201 Created

{
    "data": {
        "id": "todoapp", 
        "last_modified": 1479479506138
    }, 
    "permissions": {
        "write": [
            "basicauth:ca3731c2b1028da61b4babd187abf3341aa394cbd6c1ec5d5817c41806bab5be"
        ]
    }
}

Créer un bucket

$ http -a alice: GET :8888/v1/buckets 
HTTP/1.1 200 OK
Total-Records: 1

{
    "data": [
        {
            "id": "todoapp", 
            "last_modified": 1479479506138
        }
    ]
}

Lister les buckets à nouveau

http -a alice: PUT :8888/v1/buckets/todoapp/collections/tasks
HTTP/1.1 201 Created

{
    "data": {
        "id": "tasks", 
        "last_modified": 1479479628933
    }, 
    "permissions": {
        "write": [
            "basicauth:ca3731c2b1028da61b4babd187abf3341aa394cbd6c1ec5d5817c41806bab5be"
        ]
    }
}

Créer une collection

$ echo '{"data": {"title": "Slides kinto", "done": false}}' | \
    http -a alice: POST :8888/v1/buckets/todoapp/collections/tasks/records
HTTP/1.1 201 Created

{
    "data": {
        "done": false, 
        "id": "b4b842ea-a8d1-4c46-baec-efe53cedf8d4", 
        "last_modified": 1479479773800, 
        "title": "Slides kinto"
    }, 
    "permissions": {
        "write": [
            "basicauth:ca3731c2b1028da61b4babd187abf3341aa394cbd6c1ec5d5817c41806bab5be"
        ]
    }
}

Créer un record

$ echo '{"data": {"title": "Procrastiner un peu", "done": true}}' | \
  http -a alice: POST :8888/v1/buckets/todoapp/collections/tasks/records
HTTP/1.1 201 Created

{
    "data": {
        "done": true, 
        "id": "8fbd9559-32fe-4f92-94d2-cd963dbad529", 
        "last_modified": 1479480043970, 
        "title": "Procrastiner un peu"
    }, 
    "permissions": {
        "write": [
            "basicauth:ca3731c2b1028da61b4babd187abf3341aa394cbd6c1ec5d5817c41806bab5be"
        ]
    }
}

Créer un autre record

$ http -a alice: :8888/v1/buckets/todoapp/collections/tasks/records 
HTTP/1.1 200 OK
Total-Records: 2

{
    "data": [
        {
            "done": true, 
            "id": "8fbd9559-32fe-4f92-94d2-cd963dbad529", 
            "last_modified": 1479480043970, 
            "title": "Procrastiner un peu"
        }, 
        {
            "done": false, 
            "id": "b4b842ea-a8d1-4c46-baec-efe53cedf8d4", 
            "last_modified": 1479479773800, 
            "title": "Slides kinto"
        }
    ]
}

Lister les records

$ http -a alice: :8888/v1/buckets/todoapp/collections/tasks/records?done=true
HTTP/1.1 200 OK
Total-Records: 1

{
    "data": [
        {
            "done": true, 
            "id": "8fbd9559-32fe-4f92-94d2-cd963dbad529", 
            "last_modified": 1479480043970, 
            "title": "Procrastiner un peu"
        }
    ]
}

Filtrer les records

import KintoClient from "kinto-http"

const client = new KintoClient("https://kinto.dev.mozaws.net/v1/")

demo();

async function demo() {
  await client.createBucket("todoapp")
  const bucket = client.bucket("todoapp")
  
  await bucket.createCollection("tasks")
  const collection = bucket.collection("tasks")
  
  await collection.createRecord({title: "Slides kinto", done: false})
  await collection.createRecord({title: "Procrastiner un peu", done: true})
  
  console.log(await collection.listRecords())
  console.log(await collection.listRecords({filters: {done: true}}))
}

La même chose en JavaScript (kinto-http.js)

Généricité

  • Une nouvelle idée d'application ?
    • Hop, un nouveau bucket
    • La stack techno reste la même...
    • ... et le serveur est déjà déployé :)

Généricité

  • Et pour administrer l'ensemble des données applicatives
    • kinto-admin

kinto-admin

Synchronisation

Synchronisation

  • Protocole de synchronisation simple
  • basé sur les timestamps
  • kinto.js, offline first client for Kinto
import Kinto from "kinto"

const tasks = new Kinto({
  remote: "https://kinto.dev.mozaws.net/v1",
  bucket: "todoapp",
}).collection("tasks");

await tasks.create({label: "Try Kinto.js", done: true})

const result = await tasks.sync()

if (result.conflicts.length > 0) {
  console.warn("Uh oh, conflicts encountered!")
  await tasks.sync({strategy: "SERVER_WINS"})
}

Confidentialité

  • Chiffrement des données de bout en bout avec kinto.js
    • Quelqu'un met la main sur ses données ? Il ne peut rien en faire !

Auto-hébergement

  • Python, postgresql
  • Docker
  • Hébergeurs
    • Heroku
    • AlwaysData

Questions

Made with Slides.com