Pourquoi Rust est-il le candidat idéal pour travailler avec les API ?
\n\nSi vous pensez encore que Rust ne sert qu'à la programmation système et à remplacer le C++, vous êtes bien en retard sur la réalité. Rust a fait une entrée remarquée dans le monde du développement web et des services backend. Et il n'a pas simplement fait une entrée remarquée : il a occupé une niche où la vitesse, la fiabilité et la sécurité mémoire sont importantes.
\n\nMais soyons honnêtes : travailler avec des API en Rust ne se résume pas à « prendre une bibliothèque prête à l'emploi et oublier le reste ». C'est un art de l'équilibre entre la puissance du langage et la facilité de développement. Dans cet article, nous allons aborder trois approches principales : REST, GraphQL et gRPC. Chacune a ses avantages, et le choix dépend de votre tâche. C'est parti !
\n\nREST en Rust : un classique qui fonctionne
\n\nREST reste le style d'API le plus populaire. Il est simple, intuitif et pris en charge par pratiquement tout le monde. Pour Rust, il existe plusieurs excellents frameworks, mais le roi ici est actix-web. Il est rapide, asynchrone et dispose d'un excellent écosystème.
Écrire un service REST simple avec actix-web
\n\nCréons un mini-service pour gérer une liste de tâches (todo). Nous aurons besoin de actix-web, serde pour la sérialisation et tokio comme runtime asynchrone.
// Cargo.toml\n// [dependencies]\n// actix-web = "4"\n// serde = { version = "1", features = ["derive"] }\n// serde_json = "1"\n// tokio = { version = "1", features = ["full"] }\n\nuse actix_web::{get, post, web, App, HttpResponse, HttpServer, Responder};\nuse serde::{Deserialize, Serialize};\nuse std::sync::Mutex;\n\n#[derive(Serialize, Deserialize, Clone)]\nstruct Task {\n id: u32,\n title: String,\n completed: bool,\n}\n\nstruct AppState {\n tasks: Mutex<Vec<Task>>,\n}\n\n#[get("/tasks")]\nasync fn get_tasks(data: web::Data<AppState>) -> impl Responder {\n let tasks = data.tasks.lock().unwrap();\n HttpResponse::Ok().json(tasks.clone())\n}\n\n#[post("/tasks")]\nasync fn create_task(data: web::Data<AppState>, body: web::Json<Task>) -> impl Responder {\n let mut tasks = data.tasks.lock().unwrap();\n let new_id = tasks.len() as u32 + 1;\n let task = Task {\n id: new_id,\n title: body.title.clone(),\n completed: false,\n };\n tasks.push(task.clone());\n HttpResponse::Created().json(task)\n}\n\n#[actix_web::main]\nasync fn main() -> std::io::Result<()> {\n let state = web::Data::new(AppState {\n tasks: Mutex::new(vec![]),\n });\n\n HttpServer::new(move || {\n App::new()\n .app_data(state.clone())\n .service(get_tasks)\n .service(create_task)\n })\n .bind("127.0.0.1:8080")?\n .run()\n .await\n}\n\n\nLa beauté de ce code est qu'il est sécurisé en mémoire et ne nécessite pas de ramasse-miettes. actix-web traite des milliers de requêtes par seconde sur un seul thread, en utilisant les mécanismes asynchrones de Rust. Essayez de l'exécuter — vous serez surpris de sa rapidité, même sur du matériel modeste.
Quand REST n'est-il pas le meilleur choix ?
\n\nREST est parfait pour les opérations CRUD, mais si vous avez besoin de requêter des données de manière flexible (par exemple, des ressources imbriquées), REST commence à nécessiter de nombreux endpoints. C'est là que GraphQL entre en scène.
\n\nGraphQL en Rust : flexibilité sans douleur
\n\nGraphQL permet au client de demander exactement les données dont il a besoin. Pour Rust, le meilleur choix est async-graphql. Il s'intègre étroitement avec actix-web et fournit un DSL puissant pour décrire les schémas.
Exemple : API pour une bibliothèque de livres
\n\nSupposons que nous voulions donner aux clients la possibilité de demander des livres et des auteurs. Avec GraphQL, cela se fait avec un seul schéma.
\n\n// Cargo.toml\n// [dependencies]\n// async-graphql = "7"\n// async-graphql-actix-web = "7"\n// actix-web = "4"\n// serde = { version = "1", features = ["derive"] }\n\nuse async_graphql::{Context, EmptyMutatio