Pixel

Appli NoSQL (CouchDB) + JS léger (SolidJS)

03/05/2023

Cet article est un retour d’expérience suite à une journée innovation Frianbiz. L'un de nos collaborateurs a participé à la réalisation de ce POC ainsi qu’à la rédaction de cet article.

Présentation

L’objectif de cette journée était de mettre en place :

  • Une application Web SPA légère
  • Un stockage en ligne des données (pour garantir à l’utilisateur l’indépendance du terminal utilisé)
  • Un stockage local des données (pour garantir à l’utilisateur l’indépendance d’une connexion à Internet)
  • Permettant un accès multi-utilisateur aux mêmes données

Le choix du framework s’est porté sur SolidJS qui offre une légèreté du fait de son modèle : le code est transpilé en JavaScript pur et son exécution n’est pas dépendante du framework.

CouchDB a été choisi pour le stockage de données pour les raisons suivantes :

  • Approche NoSQL (souplesse d’évolution du schéma au fil du développement)
  • Implémentation disponible en JavaScript pour le navigateur et pour Node.js (PouchDB)
  • Propose un mécanisme de synchronisation des données

Extraits de code

Nous avons développé une application de gestion de tâches. Nous avons pu mettre en œuvre les concepts de réactivité de SolidJS :

  • Signal
const [label, setLabel] = createSignal('');

// ...

return (
	<div>
		<input                                             
		  placeholder="Ajouter une tâche"                  
		  class="border rounded"                           
		  type="text"                                      
		  value={label()}                                  
		  onChange={(e) => setLabel(e.currentTarget.value)}
		/>
	</div>
)
  • Store

const [todos, setTodos] = createStore<Todo[]>([]);

// ...

const res = await local.allDocs({ include_docs: true });                             
setTodos(res.rows.map((data) => data.doc as Todo).filter((todo) => !todo.deletedAt));

// ...

setTodos(                            
  (todo) => todo._id === response.id,
                                     
  produce((todo) => {                
    todo.status = !doc.status;       
    todo._rev = response.rev;        
  }),                                
);

Nous avons constaté à quel point la synchronisation des données est simplifiée par PouchDB/CouchDB :

const local = useLocalDatabase();  
const remote = useRemoteDatabase();

local                                                   
  .sync(remote, { live: true })                         
  .on('change', async () => await loadLocalDatabase())  
  .on('error', () => {                                  
    setSyncState(SYNC_STATES.ERROR);                    
    setTimeout(startLiveSync, 1000);                    
  });

Gestion des conflits

La modification en simultané d’un même document peut introduire des conflits.

PouchDB/CouchDB offre une gestion des conflits gestion des conflits à la fois fiable et ergonomique. Elle est fiable car elle nous protège contre la perte de données :

Because the changes are always replicated, the data is safe.

Elle est ergonomique car le moteur choisit une version qui sera la “gagnante”. Cette version “gagnante” sera la même sur l’ensemble des nœuds de la base de données :

By default, CouchDB picks one arbitrary revision as the “winner”, using a deterministic algorithm so that the same choice will be made on all peers.

On peut interroger le serveur pour lister les conflits, on obtient alors une liste de révisions en conflit :

{
  "_id": "7e5ec2db-adab-4d4a-91ec-d2fb2e8777f7",
  "_rev": "30-aafc0c3817aeb2dd9b26bd0efb16ca57",
  "_conflicts": [
    "30-a92503e416bb2634d0c0353dac9e0866",
    "27-0b2e7d1858aa1aa042b621cdea8fd7b7"
  ]
}

L’application peut alors présenter les différences à l’utilisateur afin de lui permettre de fusionner de manière intelligente les révisions en conflit.

Gestion des droits d'accès

Par défaut le serveur CouchDB est accessible publiquement (tout y est permis, même la création/suppression de base de données). CouchDB fournit un mécanisme simple de gestion des accès mécanisme simple de gestion des accès :

  • Administration du serveur (création et suppression de base de données)
  • Administration d’une base de données (modification des droits d’accès à la base de données, modification des documents de design de la base de données)
  • Utilisation d’une bases de données (lecture, modification, création, suppression de documents dans une base de données existante)

Le mécanisme décrit ci-dessus ne permet pas directement une gestion fine des droits (limiter les données visibles en fonction de l’utilisateur connecté, par exemple). Cependant CouchDB permet d’intégrer ce type de règles fonctionnelles via l’ajout de code (JavaScript) dans les documents de design ajout de code (JavaScript) dans les documents de design.

Conclusion

Cette journée a confirmé notre intérêt pour SolidJS. Ce framework propose des concepts intéressants qui méritent d’être approfondis. Cependant, le caractère compilé peut conduire à des difficultés d’analyse des dysfonctionnements une fois l’application déployée.

Le framework SolidJS a aussi montré son utilité dans sa facilité à implémenter un store en nous proposant d’office un pattern pour filtrer les données à mettre à jour au lieu de le faire manuellement.

La synchronisation de CouchDB est vraiment pratique. Lorsqu’aucun conflit ne se présente, le moteur fait le travail en toute autonomie, ce qui permet d’alléger la complexité du code applicatif.

Ces deux briques peuvent fournir une base pertinente pour la mise en place de Progressive Web Apps simples.

#CouchDB
#Appli NoSQL
#SolidJS
#App Web SPA
Avatar Sébastien Nobili Sébastien Nobili
red pixel blue pixel