Rust est un langage de programmation multiplateforme développé par Mozilla depuis 2006. Il est axé sur la performance, l'efficacité et sa fiabilité.
Il est un choix pertinent lorsque l'on veut faire du web car de nombreux frameworks très complets et viables en production existent.
Le but aujourd'hui est de faire un premier pas dans le web avec Rust en réalisant une petite page web capable d'afficher des données préalablement retrouvées depuis une base de données.
Le projet que nous allons réaliser est disponible dans sa version finale ici. Vous ne pourrez cependant pas le tester avant d’avoir suivi l’étape “Installer le client diesel”.
Rocket est un framework web très rapide à prendre en main, très bien documenté et flexible, permettant de réaliser des applis web plus ou moins complexes.
Tera est un moteur de templates très bien supporté par Rocket. Il nous permettra de créer des pages web dynamiques.
Diesel est un ORM. Si l'installation de son CLI est assez compliquée sous Windows, il est cependant l'ORM le plus utilisé pour Rust.
À noter que diesel ne supporte pas encore l'asynchrone.
On peut représenter le fonctionnement de notre future appli comme ceci :
On part du principe que rust nightly est déjà correctement installé sur votre machine (sinon consultez https://www.rust-lang.org/tools/install + exécution de la commande rustup default nightly).
Pour démarrer un projet en Rust, il suffit d'exécuter la commande cargo init dans un nouveau répertoire.
Ajoutons des dépendances à notre projet en éditant le fichier cargo.toml comme ceci :
[package]
name = "article_site"
name = "article_site"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
#Rocket
rocket = "0.5.0-rc.2"
#Templating
tera = { version = "1", default-features = true} #moteur de template
rocket_dyn_templates = {version = "0.1.0-rc.2", features = ["tera"]}
#Diesel
diesel = { version = "2.0.0", features = ["mysql"] }
#Ici on choisit mysql, en fonction de votre bdd, vous auriez pu choisir :
#["postgres"] ou ["sqlite"]
#Autres
dotenvy = "0.15" #permet de lire des fichiers d'environnements (.env)
serde = { version = "1.0", features = ["derive"] } #permet de dériver la sérialisation des objets
À la date de cet article, Diesel ne supporte que PostgreSQL, MySQL et SQLite. L’installation du CLI va être un peu laborieuse…
Le client Diesel est l’outil qui nous permettra de configurer Diesel et de mettre en place nos premières migrations.
Avant de l'installer, il va falloir remplir quelques préconditions
Diesel dépend de librairies statiques compilées pour chaque moteur SQLLangage permettant de communiquer avec une base de données. supporté. Il est possible de n’installer qu’un seul de ces moteurs. Pour ce faire, ne téléchargez alors que la lib du moteur désiré.
Les librairies que nous allons récupérer dans les prochaines parties sont à mettre dans un dossier que vous garderez. Par exemple, un répertoire “diesel_dep” dans “Mes Documents” fera l’affaire.
Les lib que nous allons utiliser peuvent aussi être trouvées (plus facilement) ailleurs sur la toile mais puisque ces sources ne sont pas vérifiées, nous vous déconseillons de procéder ainsi.
Les librairies de MySQLMoteur de gestion de base de données. sont disponibles sur le site officiel : https://downloads.mysql.com/archives/c-c/
Il faudra alors télécharger l’archive correspondante à votre système (x64 ou x32). La librairie sera alors disponible à \lib\libmysql.lib. il faudra la renommer en "mysqlclient.lib”
Il faut aussi ajouter dans le répertoire des lib le fichier libmysql.dll, nous en aurons besoin plus tard…
Vous trouverez l’archive contenant la librairie à https://www.enterprisedb.com/download-postgresql-binaries.
Une fois celle-ci extraite, l’archive sera récupérable à l’emplacement pgsql\lib\libpq.lib
Pour SQLite, c’est une autre histoire. il va falloir compiler vous-même la librairie. Vous aurez alors besoin de 2 ressources, toutes dispo sur https://www.sqlite.org/download.html :
Une fois ces deux archives téléchargées, il est nécessaire de les extraire dans le même répertoire pour la suite. Vous devriez alors avoir :
Structure de fichier avant buildPour build la lib, il vous faut ouvrir l’invite de commande VS en tapant dans la recherche Windows “Developper Command Prompt for VS” puis vous déplacer là où vous avez extrait les fichiers source avec cd /d chemin/vers/sources et exécuter la commande :
lib /DEF:sqlite3.def /OUT:sqlite3.lib /MACHINE:x64
Alors, “sqlite3.lib” apparaîtra dans le répertoire.
Lorsque nous étions allés chercher la librairie statique pour MySQL, vous deviez également copier le fichier libmysql.dll. Cette librairie dynamique est nécessaire au bon fonctionnement de Diesel. Veuillez alors ajouter le répertoire des libs à la variable d'environnement PATH de Windows.
Vous pouvez faire ceci depuis l'outil de Windows ouvert par la commande :
rundll32 sysdm.cpl,EditEnvironmentVariables
Avant de lancer l'installation, il faudra d’abord renseigner quelques variables d’environnement. Celles-ci indiqueront où trouver les librairies statiques précédemment récoltées.
Avec PowerShell on a :
setx PQ_LIB_DIR “chemin/vers/les/libs/statiques”
setx MYSQLCLIENT_LIB_DIR “chemin/vers/les/libs/statiques”
setx SQLITE3_LIB_DIR “chemin/vers/les/libs/statiques”
RÉUSSITE : la valeur spécifiée a été enregistrée. vous indique que la commande s'est bien executée.
Alors, après avoir fermé et relancé votre terminal, vous pourrez lancer l’installation du client avec :
cargo install diesel_cli --all-features
Maintenant, la commande diesel -V devrait retourner quelque chose.
À la racine du projet, lancez les commandes :
setx DATABASE_URL "mysql://user:password@url:port/db_name"
diesel setup
La variable d’environnement “DATABASE_URL” contient l’url de la base de données. Elle sera utilisée par le CLI lors de l'exécution de migration, entre autres.
par exemple,
setx DATABASE_URL "mysql://root:@127.0.0.1:3306/article_base"
diesel setup
Pour créer un nouveau fichier de migration, on exécute
diesel migration generate initial_migration
On peut ensuite éditer cette migration. Nous allons créer une table très simple
-- up.sql
CREATE TABLE liste (
id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
libelle VARCHAR(100) NOT NULL
);
INSERT INTO liste (libelle) VALUES
('a'),
('b'),
('c'),
('d'),
('e');
-- down.sql
DROP TABLE liste;
Ensuite exécutons la migration
diesel migration run
Ici on en a qu'un, mais sur de plus gros projets, les modèles s'entassent. Il est alors conseillé de les déplacer dans un ou plusieurs fichiers à part.
Vous devriez avoir la structure de fichier suivante :
/src
│ main.rs
│
└───models
mod.rs
Maintenant, il faut renseigner notre table SQL dans le code sous forme de structure :
//models/mod.rs
use diesel::prelude::*;
use serde::Serialize;
#[derive(Queryable)]
#[derive(Serialize)]
pub struct Liste {
pub id: i32,
pub libelle: String,
}
Dans un premier temps, les fichier tera sont rangés dans un répertoire templates dans la racine du projet. Commencez donc par créer ce dossier puis ajoutez y un fichier index.tera.
La syntaxe de tera est semblable à celle de twig, une documentation plutôt complète peut être trouvée ici.
Vous devriez avoir la structure de fichier suivante désormais :
Racine du projet
│ .gitignore
│ Cargo.lock
│ Cargo.toml
│ diesel.toml
│
├───migrations
│ │ .keep
│ │
│ └───<date>_initial_migration
│ down.sql
│ up.sql
│
├───src
│ │ main.rs
│ │ schema.rs
│ │
│ └───models
│ mod.rs
│
│
└───templates
index.tera
Il est possible que /src/schema.rs n’apparaisse pas encore. Pas de soucis à vous faire, il sera auto généré plus tard.
Maintenant, nous allons éditer notre index.tera pour qu'il affiche des données que l'on récupérera dans la prochaine partie.
<body>
<html>
<ul>
{% for list_item in list %}
{# list correspond à un tableau contenant des lignes de la table `Liste` #}
<li>{{ list_item.id }} - <strong>{{list_item.libelle}}</strong></li>
{% endfor %}
</ul>
</html>
</body>
Les fichiers d'environnements permettent aux serveurs de trouver des valeurs clés. Ces valeurs étant plus facilement modifiables, car toutes regroupées dans un fichier dédié et c'est aussi plus sûr de ne rien avoir écrit en dur dans le code.
Notez que l'on pourrait aussi écrire des variables d'environnements Windows. Mais l'utilisation de fichier d'environnements est préférable car plus propre.
D'ailleurs, cette partie du tuto est facultative car la variable d'env DATABASE_URL a été créée plus tôt.
Si vous voulez faire les choses bien, je vous laisse créer un fichier .env à la racine du projet et y insérer l'url de votre db :
Si vous utilisez GIT, n'oubliez pas d'ajouter le .env au .gitignore
DATABASE_URL=mysql://user:password@url:port/db_name
#[macro_use] extern crate rocket;
extern crate tera;
pub mod models;
pub mod schema;
//imports ~ rocket + templates
use rocket_dyn_templates::{Template, context};
use rocket::response::content;
//diesel
use diesel::mysql::MysqlConnection as SQLConnection;
/*
> en fonction de votre moteur de bdd vous auriez pu mettre :
use diesel::pg::PgConnection as SQLConnection;
use diesel::sqlite::SqliteConnection as SQLConnection;
*/
use diesel::prelude::*;
use dotenvy::dotenv;
//autres
use std::env;
#[get("/")]
fn index() -> content::RawHtml<Template> { //on retourne du HTML, généré par un template
use self::schema::liste::dsl::*; //permet l'utilisation d'alias
let mut c = establish_connection(); //fonction définie plus bas dans le code
let results = liste.load::<models::Liste>(&mut c).expect("Impossible de charger la liste"); //on charge TOUTES les lignes de notre table `liste`
content::RawHtml(Template::render(
"index", //nom du template (index.tera)
context! { list: results }, //on passe en argument à notre template le résultat de notre requête sql
))
}
#[launch]
fn rocket() -> _ {
rocket::build()
.mount("/", routes![index]) //on active notre route
.attach(Template::fairing()) //on ajoute le templating au cycle de vie de rocket
}
pub fn establish_connection() -> SQLConnection {
dotenv().ok(); //charge les variables présente dans le .env dans l'environnement
let database_url = env::var("DATABASE_URL") //on tente de récuperer l'url de la BDD depuis l'environnement
.expect("DATABASE_URL must be set"); //si elle n'existe pas on lève une erreur
SQLConnection::establish(&database_url) //on tente d'établir une connexion avec la BDD
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url)) //on retourne cette connexion (ou une erreur si connexion impossible)
}
Après avoir lancé le serveur via cargo run on peut se rendre sur http://127.0.0.1:8000 et voir ainsi apparaitre les valeurs que nous avions entrées en base de données.
Félicitations !
Un retour, une question ? N'hésitez pas à nous contacter pour en discuter !
Comment mettre en place l’accessibilité mobile sur IOS et Android pour les personnes en situation de handicap ?
Découvrez la planche #56 !
Si vous faites des projets informatiques ou que vous êtes simplement passionné, vous avez probablement déjà rencontré la notion « d'intégration continue » ou de « continuous integration ». Process souvent utilisé lors du développement de nos projets, on v