Introduction
Flutter est aujourd’hui l’un des frameworks incontournables de l’écosystème de développement cross platform pour le mobile.
Avec les dernières versions, il a également su présenter des solutions cohérentes pour partager son code avec des applications web et desktop.
Une corde semble cependant manquer à cet arc, à savoir la possibilité de partager du code avec la partie back d’une solution.
Il existe pourtant des solutions pour développer en Dart (le langage derrière Flutter) des API back-end depuis un certain temps, notamment à travers la librairie shelf (shelf | Dart Package).
Et récemment, une nouvelle librairie se basant sur shelf et développée par Very Good Ventures, un acteur incontournable du développement sur Flutter, a vue le jour : Dart Frog (dart_frog | Dart Package).
Nous avons souhaité tester cette solution lors d’un de nos après-midi de communautés de pratique, voici le résumé de ce que nous en avons retenu.
Présentation du sujet
L’idée de cet après midi était de mettre en place un service simple de gestion d’utilisateurs, avec un front mobile en Flutter permettant de consulter une base distante et de la manipuler (ajout / suppression / modification des éléments), un back écrit en Dart exposant un ensemble de endpoints permettant l’accès à la base, et de partager le code des entités manipulées par la base entre ces deux éléments.
Afin d’aller au bout du sujet, nous avons décidé de gérer le projet en monorepo, c’est à dire d’intégrer au sein d’un même espace git les différentes briques du projet (front / back / shared) et de simplifier leur intégration avec melos (melos | Dart Package), un outil en ligne de commande dédié à ce type de projet.
Nous sommes arrivés à un projet structuré de la façon suivante :
- common : contient tout le code commun au deux projets
- flutter_app : application Flutter
- frog_back : back développé avec Dart Frog
- melos.yaml : fichier de configuration melos
La configuration melos proprement dite est assez simple :
On référence les différents packages du projet, et on indique avec le paramètre usePubspecOverrides que melos doit résoudre les dépendances à common localement.
Mise en place de Dart Frog
Pour l’installation de Dart Frog, rien de plus simple il suffit d’installer le paquet correspondant:
On peut vérifier l’installation en lançant la commande dart frog
Pour initialiser le projet dart frog :
Il faut ensuite démarrer le serveur :
Création de routes
Dans Dart Frog, la définition des endpoints se fait grâce à l’arborescence des fichiers sous le répertoire racine /routes. Chaque nom de dossier correspond à un chemin. Ainsi, le fichier /routes/users/index.dart gérera toutes les requêtes faites sur l’endpoint /users.
routes/index.dart correspondant au endpoint /
La méthode onRequest va être appelé à chaque nouvelle requête, et permettre de récupérer les informations de l’appel, comme par exemple la méthode HTTP utilisée :
Pour créer une route dynamique, le nom du fichier doit indiquer le paramètre correspondant entre crochets. Ainsi /routes/users/[id].dart gèrera les requêtes de la forme /users/<id>.
Il suffit ensuite de définir une méthode onRequest avec un paramètre supplémentaire:
Base de données
Bien que la documentation officielle ne le mentionne pas, il est tout à fait possible d’utiliser une base de données pour sauvegarder nos modifications. Nous avons choisi ObjectBox (objectbox | Dart Package), une base de données NoSQL, pour sa simplicité de mise en place. Il suffit d’installer une bibliothèque afin que les données soient sauvegardées en local sur le poste.
Il est possible de personnaliser la fonction qui sera appelée au lancement du serveur, et ainsi de créer notre instance de store. On peut ensuite utiliser un middleware pour rendre cette instance disponible dans toute l’application serveur.
Au final, le main.dart de notre projet Dart Frog ressemble à ça :
On peut ensuite s’interfacer avec la base de données dans une route à l’aide du code suivant :
Le projet “common”
Le coeur de notre expérimentation, la librairie partagée entre les projets front et back, contient notre entité User qui ressemble à ça :
Les annotations @Entity et @Id sont fournies par ObjectBox, elles permettent d’identifier les données à intégrer en base.
Au final, notre modèle est plutôt simple, mais l’idée de pouvoir réutiliser la même base entre le back et le front reste séduisante et prend tout son sens sur des projets complexes.
Déploiement
Pour le déploiement:
dart_frog build
3 services sont proposés pour le déploiement :
- Google Cloud Run
- AWS App Runner
- Digital Ocean App Platform
Un tutoriel pour le déploiement avec chacun des services est proposé dans la documentation officielle de Dart Frog.
C’est lors du lancement de cet commande que nous avons constaté le seul problème rencontré que nous décrivons plus bas.
Tests
Avec Dart Frog, il est également possible de mettre en place des tests unitaires pour les tests des routes et des middlewares grâce au package:test et au package:mocktail.
Nous n’avons malheureusement pas eu le temps de creuser cet aspect.
Limites
La limite constatée n’est apparue qu’au moment de lancer la commande dart_frog build afin de voir ce qui était produit par l’outil : la commande n’aboutissait pas, un message d’erreur peu explicite était alors affiché :
Après quelques recherches et l’ouverture d’une issue sur le github du projet Dart Frog, nous avons fini par comprendre que, pour qu’un projet puisse être buildé, toutes ses sources devaient se trouver dans le répertoire du projet.
Ceci s’explique par le fait que le build prépare un répertoire contenant un fichier Dockerfile permettant simplement l’exécution du projet.
Docker doit avoir sous la main tous les fichiers à embarquer, donc notre architecture était mise en défaut.
La solution suggérée par l’équipe de développement de l’outil : déplacer le projet common dans le répertoire du projet frog_back.
Une fois cette manipulation mise en oeuvre, le build a pu fonctionner.
L’inconvénient de cette solution est que le projet common, pourtant utilisé par flutter_app, n’est pas clairement visible à la racine du repository.
Conclusion
Dart Frog est un outil très facile à prendre en main.
En une après midi, nous avons réussi à mettre en place un ensemble de endpoints, une base de données, et de permettre la communication avec une application Flutter.
Il s’agit d’une librairie en cours de développement, la version disponible au moment d’écrire l’article n’étant qu’une 0.3.1, mais elle montre déjà la volonté de l’équipe de fournir un outil puissant et simple à utiliser.
Vous souhaitez en savoir plus ? Contactez-nous !