Découverte de la librairie Ecto pour Elixir
by Alexandre Dedourges, DevSec
Ecto c’est quoi ? Et à quoi ça sert ?
Lorsque vous développez une application en Elixir ou tout autre type de langage de programmation, vous avez bien souvent besoin d'interagir avec une base de données. En effet, que votre application soit un SaaS (Software as a Service), un jeu, une application musicale… vous aurez souvent besoin de stocker des données ou de les utiliser. Que ce soit des données d’identités, des scores ou encore des titres. Pour les stocker, vous pourriez utiliser une base de données MySQL ou Postgres par exemple. Mais comment utiliser ces données dans votre application ? C’est là qu’intervient Ecto. Ecto est ce que l’on pourrait appeler une librairie sur certains langages comme le Python par exemple. Il fournit de nombreux outils qui vont permettre d'interagir avec les bases de données.
Ecto est donc un wrapper de base de données et un générateur de requêtes propres à Elixir. Mais son utilisation ne se limite pas à cela. C’est pourquoi nous allons voir plus en détail les possibilités que nous offre Ecto.
Une boîte à outils exclusive à Elixir
Elixir est un langage de programmation fonctionnelle, celui-ci fonctionne sur la machine virtuelle Erlang (BEAM). C’est un langage puissant et plus particulièrement pour la construction d’applications qui seront utilisées à grande échelle. En effet, il permet une maintenance et une évolutivité accessibles et simples. Son utilisation à grande échelle fait qu’il est donc souvent utilisé au côté d’une base de données. C’est donc dans ce contexte qu’il a été nécessaire de créer un outil permettant d’interagir avec celles-ci : Ecto.
Ecto offre la possibilité aux développeurs de créer des bases de données, d’y stocker des données, de les gérer, de les valider, de les convertir au bon format (SQL/Postgres Data -> Elixir Struct et Elixir Struct -> SQL/Postgres Data)...
Ecto un seul outil, mais plusieurs fonctionnalités
Ecto permet donc de réaliser plusieurs choses bien distinctes. Pour se faire, il est divisé en quatre composantes. Les changesets, les queries (requêtes), les repos et les schemas.
Changeset
Les changesets sont très utiles, car ils permettent de vérifier et valider les données avant qu'elles ne soient appliquées à la base de données. Cela permet d’éviter tout problème qui pourrait causer des dégâts pour votre application.
Query
Les Queries ou requêtes en français vont nous permettre d’interroger notre base de données via les Repos. Grâce à Ecto celles-ci n’auront pas besoin d’être écrites en MySQL ou Postgres. Les requêtes peuvent en effet être écrites avec la syntaxe Elixir. Ce qui s’avère très pratique puisque cela évite d’avoir à connaître d’autres syntaxes. Ici on a donc une seule syntaxe pour plusieurs types de base de données. De plus, les requêtes en Elixir sont sécurisées et peuvent être décomposées.
Repo
Les repositories vont permettre la « connexion » entre une base SQL et l'application Elixir. La communication repose sur un « Adapter » (Adaptateur) et les informations de connexion à la base. C’est ce qui va permettre de faire le lien entre le code en Elixir et les bases SQL. Il devient alors possible d’interroger la base via la syntaxe Elixir.
Schema
Enfin les Schemas sont utilisés pour faire coïncider les données de votre base avec des structures de données en Elixir. Sans cela il ne serait pas possible de traiter les données de la base directement en Elixir. De plus, les Schemas possèdent d’autres cas d’utilisations.
Les Repos, wrapper de base de données
Ils permettent de se connecter à la base de données et de définir ses paramètres pour pouvoir effectuer des actions entre l’application et celle-ci.
Pour définir un Repository on peut procéder comme suit:
Puis on définit la configuration du Repo dans notre environnement d’application :
Les Schemas, convertisseurs de données
Les Schémas permettent de définir sous quelle forme les données seront à traiter. Voici un exemple de Schema en Elixir :
Dans cet exemple, on cherche à définir un Utilisateur (User). Grâce à notre Schema on peut donc déjà définir que l’on va travailler sur la table « users » de notre base de données. Chaque utilisateur aura de plus la possibilité d’être défini par un nom, un prénom et un âge.
On a donc ici défini grâce à notre Schema ce qu’allait contenir notre table « users », des utilisateurs définis par leur nom, leur prénom et leur âge. Grâce à ceci nous avons donc accès à un tout nouveau type de structure. Celle-ci est générée automatiquement par Ecto dans notre application : la structure User. Cette nouvelle structure se définit comme suit :
Par exemple pour un utilisateur du nom de Cry Ptr étant âgé de 25 ans nous aurions :
Nous pourrions alors interagir avec notre base de données de la manière suivante :
Néanmoins ce n’est pas la meilleure manière de faire. En effet, tant que nous n’avons pas créé les Changesets, aucune vérification ne sera effectuée sur les données que nous voulons appliquer à la base.
Les Changesets, validateurs de données
Les Changesets sont des outils très intéressants, car ils permettent de valider les données via des filtres, des validations et des casts avant qu’elles ne soient appliquées dans la table. Les Changesets sont à définir au même endroit que les Schemas. Par exemple :
La fonction changeset commence par passer la structure à la fonction cast ainsi qu’une liste de champ autorisé. C’est ici que la validation des champs autorisés va être effectuée. La sortie attendue est un changeset.
Si certains champs fournis en paramètre ne sont pas listés en tant que paramètres acceptés, alors ces champs ne seront pas pris en compte. Par exemple, un paramètre « phone_number » ne serait pas pris en compte dans la création du changeset.
Après le cast on peut passer notre changeset dans différentes fonctions de validations afin de vérifier les valeurs de nos champs. Dans l’exemple ci-dessus, on demande la présence d’une valeur pour le nom et l'adresse mail. On vérifie que l’email est bien formaté puis que l’âge est compris entre 18 et 100. S’il est supérieur à 100 ou inférieur à 18, si l’email n’est pas valide ou si le nom et l’email ne sont pas renseignés alors la donnée et donc le changeset seront invalides. Si cela survient alors, les changements ne seront pas appliqués à la base et une erreur sera transmise.
Exemple :
Il est à noter qu’il est possible de créer plusieurs changeset pour une seule et même table. Par exemple un changeset pour la création d’un utilisateur et un autre pour la modification…
Les Queries pour interroger la base de données
Pour finir, Ecto permet d’interroger la base de données, mais plus précisément de l’interroger via des requêtes écrites en Elixir. Ce qui permet de n’utiliser qu’un seul type de langage. Grâce à ça, il n'y a pas besoin de jongler entre différentes syntaxes. On ne garde qu’une seule syntaxe et un seul langage.
Voici un exemple de requête qu’il est possible de créer en Elixir via les Queries Ecto. Cette requête va permettre de récupérer tous les utilisateurs ayant un âge supérieur à 18 ou n’ayant pas d’adresse mail renseignée. Cette requête va d’abord passer par notre Repo pour qu’elle soit « traduite » dans le bon langage. Puis elle sera utilisée pour interroger la base et renvoyer tous les résultats obtenus.
Grâce à Ecto il est aussi possible d’interroger directement une table. Mais il sera nécessaire de préciser dans la requête les données à récupérer.
Enfin l’utilisation d’Ecto permet d’éviter les attaques comme les Injections SQL. Ce type d’attaque était classé n° 1 et n° 3 en 2017 et 2021 par l’OWASP (Open Web Application Security Project) dans son « Top 10 Web Application Security Risks ».
Ecto sans base de données.
Une particularité d’Ecto est le fait qu’il puisse être utilisé sans base de données. En effet, les Schemas et les Changesets peuvent être utilisés de différentes façons. Dans le cas où vous désirez traiter des données ayant un format bien précis sans forcément les persister dans une base par exemple. À l’aide des différentes fonctions de validations mises à disposition par Ecto, vous pourrez valider et filtrer efficacement vos données.
Ecto pas-à-pas
Les bases
Pour commencer à utiliser Ecto dans un Projet, vous pouvez commencer par utiliser la commande Mix afin de créer une application.
Ensuite rendez-vous dans le dossier nouvellement créé « project ». Dans ce dossier devrait se trouver un fichier « mix.exs ». Il va falloir modifier ce fichier afin que vous puissiez utiliser Ecto et communiquer avec une base Postgres depuis votre application. Pour se faire, il faut ajouter les dépendances suivantes au projet :
Une fois fait, il faut désormais appliquer ces dépendances au projet via la commande :
Création du Repo
Pour créer un Repo on dispose d’une commande qui le crée automatiquement.
Cette commande va générer automatiquement une configuration de base pour la connexion à la base de données dans le fichier « config/config.exs » ainsi qu’un « Adapter ».
Vous devrez modifier cette configuration en fonction des paramètres de votre base de données. Et ajouter la ligne suivante dans le fichier :
Cette ligne nous sera utile par la suite pour pouvoir exécuter des commandes Ecto en ligne de commande.
L’Adapter sera lui déclaré dans le module Project.Repo défini par le fichier « lib/project/repo.ex »
On doit maintenant indiquer à notre application qu’il faut lancer Ecto quand celle-ci démarre. Pour cela on va modifier l’arbre de supervision (supervision tree) de notre application.
Celui-ci se situe dans le fichier « lib/friends/application.ex ».
Nous pouvons maintenant créer notre base de données avec la commande suivante :
Création et modification des tables
Pour créer et modifier les tables, nous avons un autre outil qui est très pratique dans Ecto : les Migrations. Chaque fois que nous aurons à modifier une table ou des tables, nous devrons créer un fichier de migration et l'exécuter.
Pour cela il est possible d'exécuter la commande :
Cela doit avoir généré un nouveau fichier ressemblant à ceci :
priv/repo/migrations/20220606160123_create_users.exs
Celui-ci se présente sous la forme suivante :
Maintenant, imaginons que nous souhaitons créer une table « User ». Pour ce faire, nous devons modifier ce fichier de migration afin de lui exprimer les changements que nous voulons effectuer. On pourrait alors avoir le fichier suivant :
On peut maintenant exécuter les migrations à l’aide de la commande :
Création des Schemas
Il est désormais possible de créer le fichier de Schema «** lib/project/user.ex **». Celui-ci va nous permettre de mapper les données de notre base à une structure Elixir.
Notre Schema ressemblera donc à ceci :
Création des Changesets
Maintenant que notre Schema est créé, on peut lui attribuer des validations, des filtres…
Pour ce faire nous allons avoir besoin des Changesets. Il est très commun de définir des Changesets avec les Schemas pour s’assurer que les données que nous voulons utiliser sont correctes. Il est possible de créer des fonctions changesets directement pour pouvoir les réutiliser au besoin. La fonction de changeset la plus basique est la suivante :
Cette fonction prend en entrée une structure (dans notre cas ce serait un user) et des paramètres. Puis elle retourne un changeset.
À partir de ces changesets, il est possible d’effectuer de nombreuses actions de vérification… Par exemple, nous voulons que l’email et le nom d’un utilisateur soient toujours présents. Nous pouvons alors imaginer le changeset suivant :
Dorénavant lorsque nous essaierons de créer un utilisateur avec un nom vide ou un email vide le changeset obtenu en sortie sera invalide. Il sera donc impossible d’insérer cet utilisateur dans la base de données.
De nombreuses autres possibilités sont réalisables à partir d’Ecto, mais les étapes ci-dessus représentent les actions les plus basiques d’Ecto. Si vous voulez en savoir plus, n'hésitez pas à consulter la documentation en ligne.
Ecto un outil puissant pour les bases de données, mais pas que
Ecto est donc un outil très puissant et très intéressant qui permettra à toutes les applications l’utilisation des bases de données. C’est un outil indispensable à tous les développeurs utilisant Elixir pour travailler avec des bases de données. Chez Cryptr nous utilisons Ecto pour garantir rapidité, fluidité, évolutivité, mais aussi sécurité. Les données d’identités qui sont stockées dans le cadre, par exemple, des connexions SSO sont alors plus en sécurité.
Alors prêt à en apprendre plus ? On vous en dit plus chez Cryptr.
Add enterprise SSO for free
Cryptr simplifies user management for your business: quick setup, guaranteed security, and multiple free features. With robust authentication and easy, fast configuration, we meet businesses' security needs hassle-free.