Rust permet de créer un serveur HTTP rapide et sûr en quelques centaines de lignes. Le point faible arrive souvent après : obtenir une boucle de feedback rapide pour tester les endpoints, les statuts HTTP, les payloads JSON et l’authentification sans relancer toute la chaîne Rust à chaque modification. Pour livrer une API, pas seulement un binaire, ajoutez une couche de test HTTP externe qui parle au serveur en cours d’exécution.
Ce guide montre un workflow complet de test d’API Rust avec Apidog : connecter un serveur Axum ou Actix, créer des requêtes réutilisables, valider le JSON produit par Serde, gérer un JWT, mocker des endpoints pour le frontend, puis exécuter le tout en CI.
Si vous venez d’un workflow Postman ou curl, Apidog ajoute aussi une couche de conception : spécification OpenAPI générée depuis les requêtes enregistrées, URL de mock partageables et environnements d’équipe. La migration depuis Postman est un sujet séparé ; ici, on se concentre sur Rust.
TL;DR
- Lancez votre serveur Rust localement (
cargo run) et configurezhttp://localhost:3000commebaseUrldans Apidog. - Créez une première requête
GET /healthzpour valider l’environnement. - Ajoutez vos endpoints JSON, puis écrivez des assertions sur les statuts et la forme des réponses.
- Stockez le JWT dans une variable
{{token}}et appliquez l’authentification Bearer au niveau du dossier. - Mockez les handlers Rust non terminés pour débloquer le frontend.
- Regroupez les requêtes dans un scénario de test et lancez-le en CI avec
apidog-cli.
Pourquoi tester une API Rust en dehors de cargo test
cargo test reste indispensable pour les tests unitaires et d’intégration Rust. Mais pour vérifier le contrat HTTP réel — code de statut, headers, forme JSON, messages d’erreur, auth, CORS — il devient vite verbeux.
Avec Apidog, vous testez le serveur tel qu’il tourne :
Les tests de contrat sont découplés de la compilation.
Vous exécutez des requêtes HTTP contre un binaire déjà lancé.Les mocks sont partageables.
Le frontend peut consommer une URL stable même si le handler Rust n’est pas encore prêt.OpenAPI peut être généré depuis les requêtes.
Vous obtenez une spec OpenAPI 3.1 basée sur ce que vous testez réellement, sans annoter toutes vos routes avecutoipaouaide.
Étape 1 : Ajouter le serveur Rust comme environnement Apidog
Démarrez une API Axum minimale :
use axum::{routing::get, Router};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() {
let app = Router::new().route("/healthz", get(|| async { "ok" }));
let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
Dans Apidog :
- Créez un nouveau projet.
- Ouvrez la gestion des environnements.
- Ajoutez un environnement
Rust Local.
| Variable | Valeur |
|---|---|
baseUrl |
http://localhost:3000 |
token |
laisser vide pour l’instant |
apiVersion |
v1 |
Ajoutez aussi un environnement Rust Staging avec l’URL de staging. Les variables étant scopées par environnement, vous pouvez passer du local au staging sans modifier les requêtes.
Étape 2 : Créer le premier test HTTP
Créez un dossier Rust API, puis une requête :
- Méthode :
GET - URL :
{{baseUrl}}/healthz
Envoyez la requête. Le serveur doit répondre :
ok
avec un statut :
200 OK
Enregistrez la requête sous le nom health-check.
Si vous obtenez connection refused, vérifiez :
- que le serveur tourne ;
- que le port est bien
3000; - que le serveur écoute sur
0.0.0.0:3000plutôt que seulement127.0.0.1:3000.
Cette requête devient votre test de fumée : si elle échoue, inutile de lancer le reste de la suite.
Étape 3 : Tester un endpoint JSON avec Serde
Ajoutez un endpoint POST /users côté Rust :
use axum::{extract::Json, routing::post, Router};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct CreateUser {
name: String,
email: String,
}
#[derive(Serialize)]
struct User {
id: u64,
name: String,
email: String,
}
async fn create_user(Json(payload): Json<CreateUser>) -> Json<User> {
Json(User {
id: 1,
name: payload.name,
email: payload.email,
})
}
let app = Router::new().route("/users", post(create_user));
Dans Apidog, créez une requête :
- Méthode :
POST - URL :
{{baseUrl}}/users - Body JSON :
{
"name": "Ada Lovelace",
"email": "ada@example.com"
}
Envoyez la requête et enregistrez-la sous create-user.
Ajoutez ensuite des assertions dans l’onglet Tests :
pm.test("Status is 200", () => {
pm.expect(pm.response.code).to.eql(200);
});
pm.test("Body has id, name, email", () => {
const body = pm.response.json();
pm.expect(body).to.have.property("id");
pm.expect(body.name).to.eql("Ada Lovelace");
pm.expect(body.email).to.match(/^[^@]+@[^@]+$/);
});
Ces assertions protègent le contrat public. Si vous changez plus tard un attribut Serde, par exemple avec #[serde(rename_all = "camelCase")], la suite Apidog détectera la dérive de réponse.
Étape 4 : Couvrir les erreurs de validation Serde
Testez aussi les entrées invalides. Créez trois requêtes à partir de create-user.
| Requête | Body | Attendu |
|---|---|---|
create-user-missing-email |
{ "name": "Ada" } |
422, le corps mentionne missing field email
|
create-user-extra-field |
{ "name": "Ada", "email": "a@b.c", "admin": true } |
200 si #[serde(deny_unknown_fields)] est absent ; 422 sinon |
create-user-wrong-type |
{ "name": 1, "email": "a@b.c" } |
422, mentionne invalid type: integer
|
Exemple d’assertion pour le champ manquant :
pm.test("Rejects missing email", () => {
pm.expect(pm.response.code).to.eql(422);
pm.expect(pm.response.text()).to.include("missing field");
});
Ce type de test documente votre politique de validation réelle. Si vous activez deny_unknown_fields plus tard, le test correspondant échouera et signalera un changement de contrat.
Étape 5 : Tester les routes protégées par JWT
Les API Rust en production exposent souvent des routes derrière un middleware d’authentification. Exemple avec un extracteur basé sur cookie et jsonwebtoken :
use axum::{Json, http::StatusCode};
use axum_extra::extract::cookie::PrivateCookieJar;
use jsonwebtoken::{decode, DecodingKey, Validation};
async fn me(jar: PrivateCookieJar) -> Result<Json<User>, StatusCode> {
let token = jar.get("token").ok_or(StatusCode::UNAUTHORIZED)?;
let claims = decode::<Claims>(
token.value(),
&DecodingKey::from_secret(b"secret"),
&Validation::default(),
)
.map_err(|_| StatusCode::UNAUTHORIZED)?;
Ok(Json(User {
id: claims.claims.sub,
name: "Ada".into(),
email: "ada@example.com".into(),
}))
}
Dans Apidog, évitez de générer le JWT manuellement. Ajoutez un script de pré-requête au niveau du dossier :
const jwt = require("jsonwebtoken");
const token = jwt.sign(
{
sub: 1,
exp: Math.floor(Date.now() / 1000) + 3600
},
"secret"
);
pm.environment.set("token", token);
Puis configurez l’authentification du dossier :
- Type : Bearer Token
- Token :
{{token}}
Toutes les requêtes du dossier héritent maintenant du JWT.
Pour tester le cas non autorisé, créez une requête séparée qui désactive l’auth ou remplace {{token}} par une valeur invalide, puis ajoutez :
pm.test("Rejects invalid token", () => {
pm.expect(pm.response.code).to.eql(401);
});
Pour approfondir ce sujet, consultez comment tester l’authentification JWT dans les API.
Étape 6 : Tester le streaming et les Server-Sent Events
Les frameworks web Rust gèrent bien le streaming. Avec Axum, une réponse Sse encapsule un futures::Stream et émet des chunks text/event-stream.
Le format réseau ressemble à ceci :
data: { ... }
data: { ... }
event: done
data: {}
Dans Apidog :
- Créez une requête
GETvers votre endpoint SSE. - Envoyez-la.
- Vérifiez que le panneau de réponse passe en mode streaming lorsque le
Content-Typevauttext/event-stream.
À vérifier pendant le test :
- le premier chunk arrive dans le délai attendu ;
- un événement final comme
event: doneest bien reçu ; - le flux ne reste pas ouvert indéfiniment ;
- le timeout de la requête est assez strict pour faire échouer un stream bloqué.
Si votre API utilise WebSocket plutôt que SSE, utilisez le type de requête WebSocket d’Apidog. Le principe reste identique : ouvrir la connexion, enregistrer la séquence de messages, vérifier les réponses.
Étape 7 : Mocker l’API Rust pour débloquer le frontend
Les mocks Apidog permettent au frontend d’avancer avant que le handler Rust ne soit terminé.
À partir de la requête create-user :
- Faites un clic droit sur la requête.
- Activez Smart Mock.
- Partagez l’URL générée, par exemple :
https://mock.apidog.com/m1/<projectId>/users
Le mock renvoie une réponse basée sur l’exemple enregistré.
Pour un mock dynamique, utilisez Advanced Mock avec un script :
return {
id: Math.floor(Math.random() * 10000),
name: body.name,
email: body.email,
createdAt: new Date().toISOString()
};
Le frontend peut alors envoyer un POST avec le même body que celui attendu par le serveur Rust. Quand le vrai handler est prêt, il suffit de remplacer l’URL de base par http://localhost:3000.
Le même workflow est présenté dans les articles sur la création et le test d’une API Spring Boot et le workflow général de test d’API.
Étape 8 : Créer un scénario de test CI
Un scénario de test Apidog enchaîne plusieurs requêtes avec des variables partagées.
Créez un scénario avec cet ordre :
-
health-check- assert
200
- assert
-
create-user- assert
200 - capturer
body.iddans une variable
- assert
-
create-user-missing-email- assert
422
- assert
-
me- utiliser le script JWT de pré-requête
- assert
200 - vérifier que l’
idrenvoyé correspond à l’idcapturé si votre logique métier le permet
-
Requête SSE
- vérifier que le flux se termine dans les 5 secondes
Exemple de capture d’id :
pm.test("Capture user id", () => {
const body = pm.response.json();
pm.expect(body).to.have.property("id");
pm.environment.set("userId", body.id);
});
Exportez ensuite le scénario en JSON et versionnez-le dans le dépôt :
tests/apidog/contract.json
Exemple GitHub Actions :
- name: Run API contract tests
run: |
cargo build --release
./target/release/myserver &
sleep 2
apidog-cli run tests/apidog/contract.json --env "Rust Local"
Chaque pull request qui modifie un handler est alors testée contre un vrai binaire Rust. Si un renommage Serde, un changement de statut HTTP ou une régression JWT casse le contrat, la CI échoue avant la fusion.
Étape 9 : Générer OpenAPI depuis les requêtes enregistrées
Quand les requêtes sont stables :
- Ouvrez le menu d’export Apidog.
- Choisissez OpenAPI 3.1.
- Exportez le document.
Vous obtenez une spécification basée sur les requêtes et réponses testées. Elle peut ensuite servir à générer des clients typés TypeScript, Swift, Kotlin ou Python.
Si vous voulez versionner la spec dans le dépôt Rust, exécutez l’export en CI :
apidog-cli export --format openapi --output openapi.json
Le build Rust ne change pas, mais les consommateurs de l’API disposent d’un contrat à jour.
FAQ
Apidog fonctionne-t-il avec Axum et Actix-web ?
Oui. Apidog parle HTTP, pas Rust. Axum, Actix-web, Rocket, Warp, Poem ou Loco fonctionnent de la même manière tant qu’ils exposent un endpoint HTTP.
La seule attention côté local : liez le serveur à 0.0.0.0 si Apidog, Docker ou d’autres outils doivent y accéder.
Comment tester les handlers qui paniquent ?
Ajoutez CatchPanicLayer de tower-http devant le routeur. La panique peut alors devenir une réponse 500 testable.
Sinon, la connexion sera coupée et Apidog signalera une erreur réseau. C’est aussi un signal utile si votre contrat interdit les interruptions brutales.
Puis-je tester un binaire Rust dans Docker ?
Oui. Pointez baseUrl vers le port exposé du conteneur.
Avec Docker Compose, utilisez soit :
- le port mappé sur l’hôte ;
- le même réseau Docker que celui utilisé par l’exécuteur Apidog.
Qu’en est-il du gRPC ?
Apidog dispose d’un type de requête gRPC. Importez vos fichiers .proto, choisissez le service et la méthode, remplissez la payload, puis envoyez la requête.
Les environnements, l’authentification et les scénarios de test suivent le même modèle que pour REST.
Le scénario Apidog remplace-t-il cargo test ?
Non.
Gardez les tests unitaires et d’intégration Rust dans cargo test. Utilisez Apidog pour tester la surface d’exécution HTTP :
- forme JSON ;
- statuts HTTP ;
- headers ;
- erreurs de validation ;
- authentification ;
- mocks ;
- streaming.
Les deux couches détectent des bugs différents.
Apidog est-il gratuit pour les projets open-source Rust ?
Oui. Le client Apidog est gratuit pour les particuliers et les petites équipes. Les scénarios de test, les mocks et l’export OpenAPI font partie du niveau gratuit.
En résumé
Une API Rust a besoin de tests proches du protocole HTTP réel. Avec Apidog, vous pouvez créer une collection de requêtes, ajouter des assertions, générer des mocks, exporter OpenAPI et exécuter le contrat en CI contre un binaire Rust vivant.
Téléchargez Apidog, pointez-le vers votre serveur Rust, puis commencez par GET /healthz. En quelques requêtes, vous obtenez un contrat testable, partageable et découplé de cargo.
Top comments (0)