Points d’accès et modèles
Routes et données
Points d’accès et modèles est une leçon Learn Rust Coding gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Learn Rust Coding, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Learn Rust Coding comprend 4 leçons au total.
Routes et modèles de données
Une API est définie par ses points d’accès (URL et méthodes HTTP) et par les modèles (formes des données) qui y circulent. Dans cette leçon, vous définirez des modèles de requête et de réponse avec serde et mettrez en place des routes de type CRUD dans Axum.
Définir un modèle
Un modèle est une simple structure Rust. Dérivez Serialize pour pouvoir le convertir en JSON dans les réponses, et Deserialize pour pouvoir l’analyser depuis les corps des requêtes. Les noms des champs correspondent directement aux clés JSON.
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone)]
struct Todo {
id: u32,
title: String,
done: bool,
}Séparer les types de requête et de réponse
Les clients ne doivent pas envoyer l’id attribué par le serveur lors de la création d’une ressource. Utilisez une structure d’entrée distincte pour le corps de la requête et le modèle complet pour les réponses. Le contrat reste ainsi clair et les clients ne peuvent pas définir des champs qui ne devraient pas l’être.
use serde::Deserialize;
#[derive(Deserialize)]
struct CreateTodo {
title: String,
}
// The handler assigns the id and sets done = false.GET : lister des ressources
Un gestionnaire GET /todos renvoie toute la collection sous forme de tableau JSON. Il lit l’état partagé, copie rapidement les données hors du verrou, puis les enveloppe dans Json.
use axum::{extract::State, Json};
use std::sync::{Arc, Mutex};
type Store = Arc<Mutex<Vec<Todo>>>;
#[derive(Clone, serde::Serialize)]
struct Todo { id: u32, title: String, done: bool }
async fn list_todos(State(store): State<Store>) -> Json<Vec<Todo>> {
let todos = store.lock().unwrap().clone();
Json(todos)
}POST : créer une ressource
Un gestionnaire POST /todos lit le corps JSON avec l’extracteur Json, attribue un nouvel identifiant, stocke l’élément et le renvoie avec le statut 201 Created. Le tuple (StatusCode, Json<T>) permet de définir à la fois le statut et le corps.
use axum::{extract::State, Json, http::StatusCode};
async fn create_todo(
State(store): State<Store>,
Json(input): Json<CreateTodo>,
) -> (StatusCode, Json<Todo>) {
let mut todos = store.lock().unwrap();
let id = todos.len() as u32 + 1;
let todo = Todo { id, title: input.title, done: false };
todos.push(todo.clone());
(StatusCode::CREATED, Json(todo))
}Paramètres de chemin
Pour récupérer une seule ressource, capturez une partie de l’URL avec un paramètre de chemin. Déclarez-le dans la route sous la forme /todos/{id} et extrayez-le avec l’extracteur Path. Le type demandé, ici u32, est analysé automatiquement.
use axum::extract::{Path, State};
use axum::{Json, http::StatusCode};
async fn get_todo(
State(store): State<Store>,
Path(id): Path<u32>,
) -> Result<Json<Todo>, StatusCode> {
let todos = store.lock().unwrap();
match todos.iter().find(|t| t.id == id) {
Some(t) => Ok(Json(t.clone())),
None => Err(StatusCode::NOT_FOUND),
}
}Paramètres de requête
Le filtrage et la pagination utilisent la chaîne de requête, par exemple /todos?done=true. Capturez-la avec l’extracteur Query dans une structure Deserialize. Les champs facultatifs utilisent Option, ce qui permet d’omettre certains paramètres.
use axum::extract::{Query, State};
use axum::Json;
use serde::Deserialize;
#[derive(Deserialize)]
struct Filter { done: Option<bool> }
async fn filtered(
State(store): State<Store>,
Query(f): Query<Filter>,
) -> Json<Vec<Todo>> {
let todos = store.lock().unwrap();
let out = todos.iter()
.filter(|t| f.done.map_or(true, |d| t.done == d))
.cloned().collect();
Json(out)
}PUT et DELETE
La mise à jour utilise PUT /todos/{id} avec un corps ; la suppression utilise DELETE /todos/{id}. Les deux recherchent l’élément par son identifiant et renvoient 404 s’il est introuvable. Une suppression renvoie généralement 204 No Content en cas de réussite.
use axum::extract::{Path, State};
use axum::http::StatusCode;
async fn delete_todo(
State(store): State<Store>,
Path(id): Path<u32>,
) -> StatusCode {
let mut todos = store.lock().unwrap();
let before = todos.len();
todos.retain(|t| t.id != id);
if todos.len() < before { StatusCode::NO_CONTENT }
else { StatusCode::NOT_FOUND }
}Relier les routes
Enregistrez chaque gestionnaire sur le routeur. Regroupez les méthodes qui partagent un même chemin : /todos gère la liste et la création, tandis que /todos/{id} gère la récupération, la mise à jour et la suppression. Ajoutez le magasin partagé avec .with_state.
use axum::{routing::get, Router};
fn build(store: Store) -> Router {
Router::new()
.route("/todos", get(list_todos).post(create_todo))
.route("/todos/{id}",
get(get_todo).delete(delete_todo))
.with_state(store)
}Valider les entrées
Ne faites jamais confiance aux données des clients. Vérifiez-les dans le gestionnaire et renvoyez 400 Bad Request lorsqu’elles sont invalides. Ici, nous refusons un titre vide avant tout stockage, afin d’empêcher les mauvaises données d’entrer dans le système.
use axum::{Json, extract::State, http::StatusCode};
async fn create_validated(
State(store): State<Store>,
Json(input): Json<CreateTodo>,
) -> Result<(StatusCode, Json<Todo>), StatusCode> {
if input.title.trim().is_empty() {
return Err(StatusCode::BAD_REQUEST);
}
let mut todos = store.lock().unwrap();
let id = todos.len() as u32 + 1;
let todo = Todo { id, title: input.title, done: false };
todos.push(todo.clone());
Ok((StatusCode::CREATED, Json(todo)))
}Des réponses d’erreur cohérentes
Renvoyer uniquement des codes de statut fonctionne, mais les API de production renvoient aussi un corps JSON décrivant l’erreur. Une approche courante consiste à utiliser une énumération d’erreur personnalisée qui implémente IntoResponse, en associant chaque variante à un statut et à un message. Les clients obtiennent ainsi des erreurs prévisibles et lisibles par les machines.
use axum::response::{IntoResponse, Response};
use axum::http::StatusCode;
use axum::Json;
use serde_json::json;
enum ApiError { NotFound, BadRequest(String) }
impl IntoResponse for ApiError {
fn into_response(self) -> Response {
let (status, msg) = match self {
ApiError::NotFound => (StatusCode::NOT_FOUND, "not found".to_string()),
ApiError::BadRequest(m) => (StatusCode::BAD_REQUEST, m),
};
(status, Json(json!({ "error": msg }))).into_response()
}
}Vérification rapide
Vérifiez votre compréhension des points d’accès et des modèles.
Récapitulatif
Vous avez défini des points d’accès et des modèles :
- Les modèles sont des structures qui dérivent
Serialize/Deserialize; utilisez des types d’entrée distincts. Json,Path,QueryetStateextraient les données des requêtes.- Associez les opérations CRUD à GET/POST/PUT/DELETE avec les codes de statut appropriés.
- Validez les entrées et renvoyez
400lorsque les données sont incorrectes. - Un type d’erreur personnalisé qui implémente
IntoResponsefournit des erreurs JSON cohérentes.
Questions Fréquemment Posées
La leçon « Points d’accès et modèles » est-elle gratuite ?
Oui — le texte complet de « Points d’accès et modèles » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Learn Rust Coding, passe à CoddyKit PRO. Le cours Learn Rust Coding comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Points d’accès et modèles » ?
Routes et données Tu pratiques Learn Rust Coding avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Learn Rust Coding ?
Aucune expérience préalable n'est requise. Learn Rust Coding sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.
Combien de temps prend la leçon « Points d’accès et modèles » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Learn Rust Coding ?
Oui. Chaque leçon Learn Rust Coding inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Configuration du projet
- Points d’accès et modèles
- Intégration de la base de données
- Tester l’API