Rust bietet Ihnen einen schnellen, typsicheren HTTP-Server in wenigen hundert Zeilen. Was es Ihnen nicht bietet, ist ein schneller Feedback-Loop zum Testen dieses Servers. Der Kompilierungszyklus ist lang, cargo test führt bei einer einzelnen Trait-Änderung alles neu aus, und die meisten Rust-HTTP-Frameworks zwingen Sie dazu, für jeden Endpunkt einen separaten Integrationstest zu schreiben, bevor Sie ihn überhaupt einmal aufgerufen haben. Wenn Sie eine API und nicht nur eine Binärdatei bereitstellen möchten, benötigen Sie ein Tool, das außerhalb der Rust-Toolchain existiert und mit dem laufenden Server kommuniziert.
Dieser Leitfaden führt Sie durch den vollständigen Rust-API-Test-Workflow innerhalb von Apidog: Apidog auf Ihren Axum- oder Actix-Server richten, Anfragen an Ihre Endpunkte stellen, Serde-serialisiertes JSON validieren, JWT-Authentifizierung handhaben, Endpunkte mocken, damit das Frontend weiterarbeiten kann, während Sie den Handler fertigstellen, und das Ganze als CI-Testszenario verpacken. Am Ende haben Sie ein wiederverwendbares Apidog-Projekt, das Vertragsabweichungen erkennt, bevor cargo build --release abgeschlossen ist.
Wenn Sie von einem Postman- oder curl-Workflow kommen, erhalten Sie auch Apidogs Design-First-Funktionen kostenlos: eine aus Ihren gespeicherten Anfragen generierte OpenAPI-Spezifikation, teilbare Mock-URLs und Team-Umgebungen. Die Postman-Migrationsgeschichte überspringen wir für eine separate Lektüre; dieser Beitrag konzentriert sich auf Rust.
TL;DR
- Führen Sie Ihren Rust-Server lokal aus (
cargo rungegen ein Axum- oder Actix-Web-Projekt), fügen Sie die Basis-URLhttp://localhost:3000als Apidog-Umgebung hinzu und speichern Sie alle Geheimnisse als Variablen. - Erstellen Sie die erste Anfrage gegen
GET /healthz, speichern Sie sie und verwenden Sie die Authentifizierung und Basis-URL für jeden Handler im Ordner wieder. - Für JSON-Endpunkte fügen Sie Ihre Serde-Struktur in den Body-Editor von Apidog ein und bestätigen Sie die Antwortform mit Test-Skripten, die nach jedem Senden ausgeführt werden.
- Für geschützte Routen erstellen Sie einmal ein JWT, speichern es als
{{token}}und wenden die Bearer-Authentifizierung auf Ordnerebene an, damit jeder Test diese erbt. - Mocken Sie unfertige Rust-Handler in Apidog, damit Ihr Frontend-Team echte Antworten rendern kann, bevor der Handler sauber kompiliert wird.
- Speichern Sie den Arbeitsbereich als Testszenario, exportieren Sie ihn und führen Sie ihn in CI mit
apidog-cliaus. Jeder PR, der einen Handler betrifft, erhält nun vor dem Merge eine Vertragsprüfung.
Warum eine Rust-API außerhalb der Rust-Toolchain testen
cargo test ist gut. Es ist aber auch langsam, für Nicht-Rust-Teammitglieder undurchsichtig und um Code statt HTTP herum aufgebaut. Wenn Sie überprüfen möchten, ob Ihr Handler den richtigen Statuscode, die richtige JSON-Form, die richtigen Header und die richtige Fehlermeldung zurückgibt, wenn die Eingabe fehlerhaft ist, schreiben Sie für jeden Fall einen neuen tower::ServiceExt::oneshot-Aufruf. Dann pflegen Sie diesen Test, wenn sich der Handler ändert. Dann schreiben Sie ihn erneut in JavaScript, damit das Frontend einen Mock aufrufen kann.
Apidog bietet Ihnen eine einzige Vertragsschicht auf dem laufenden Server. Die Anfrage existiert einmal. Zusicherungen leben neben der Anfrage. Frontend-Teammitglieder öffnen dasselbe Projekt und sehen dieselben Anfragen wie Sie. Wenn Serde in drei Wochen ein #[serde(rename_all = "camelCase")]-Attribut erhält, ist der Test, der fehlschlägt, der in Apidog und nicht der, der in Produktion geht.
Drei konkrete Gründe, Apidog zu einem Rust-Workflow hinzuzufügen:
- Vertragsprüfungen entkoppeln sich vom Build. Apidog läuft gegen eine laufende Binärdatei. Sie müssen nicht mehr auf
rustcwarten, um zu überprüfen, ob Ihr Endpunkt immer noch200zurückgibt. - Mocks sind teilbar. Ein Frontend-Entwickler in einer anderen Zeitzone erhält eine URL, die das richtige JSON zurückgibt, und keine Slack-Nachricht, die besagt: „Der Handler ist noch nicht fertig.“
- OpenAPI kostenlos. Apidog kann aus den gespeicherten Anfragen ein OpenAPI 3.1-Dokument generieren. Sie übergeben dies jedem, der einen typisierten Client wünscht, ohne auf jeder Route eine
utoipa- oderaide-Annotation schreiben zu müssen.
Schritt 1: Ihren Rust-Server als Apidog-Umgebung hinzufügen
Starten Sie Ihre Rust-API. Für ein Axum-Projekt sieht der Boilerplate-Code so aus:
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();
}
Öffnen Sie Apidog, erstellen Sie ein neues Projekt, öffnen Sie dann die Umgebungsverwaltung (Dropdown oben rechts) und fügen Sie eine Umgebung namens Rust Local hinzu:
| Variable | Wert |
|---|---|
baseUrl |
http://localhost:3000 |
token |
vorerst leer lassen |
apiVersion |
v1 |
Fügen Sie eine zweite Umgebung namens Rust Staging mit der bereitgestellten Basis-URL hinzu. Apidog weist Variablen pro Umgebung zu, sodass Sie mit einem Dropdown-Klick von Lokal zu Staging wechseln. Kein Suchen und Ersetzen in gespeicherten Anfragen.
Schritt 2: Den ersten Endpunkt aufrufen
Erstellen Sie einen Ordner namens Rust API innerhalb des Projekts, dann eine neue Anfrage:
- Methode:
GET - URL:
{{baseUrl}}/healthz
Klicken Sie auf Senden. Wenn Ihr Server läuft, erhalten Sie eine 200 mit dem Body ok. Speichern Sie dies als health-check. Dies ist der einfachstmögliche Smoke-Test und bestätigt, dass die Umgebung und die Basis-URL funktionieren, bevor Sie etwas Interessanteres schreiben.
Wenn Sie einen „Connection refused“-Fehler erhalten, ist Ihr Server nicht an 0.0.0.0 gebunden oder der Port ist falsch. Rusts Standard TcpListener::bind("127.0.0.1:3000") lehnt Anfragen ab, die von etwas kommen, das auf einer anderen Schnittstelle zu localhost aufgelöst wird; binden Sie an 0.0.0.0 für die lokale Entwicklung, damit Apidog und Docker-Container darauf zugreifen können.
Schritt 3: JSON-Anfrage und -Antwort mit Serde testen
Die häufigste Form einer Rust-API ist ein JSON-in, JSON-out-Handler, der von einer Serde-Struktur unterstützt wird. Fügen Sie eine POST /users-Route hinzu:
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));
Erstellen Sie in Apidog eine Anfrage:
- Methode:
POST - URL:
{{baseUrl}}/users - Body (JSON):
{
"name": "Ada Lovelace",
"email": "ada@example.com"
}
Senden Sie es. Sie erhalten das User-JSON zurück. Speichern Sie es als create-user.
Öffnen Sie nun den Tab „Tests“ und fügen Sie Zusicherungen hinzu:
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(/^[^@]+@[^@]+$/);
});
Wenn das nächste Mal jemand #[serde(rename_all = "camelCase")] zur Struktur hinzufügt und sich Ihre Antwortform von user_id zu userId ändert, schlägt dieser Test fehl, bevor die Änderung ausgeliefert wird. Das ist der Vertrag, den Ihnen Apidog bietet und den cargo test nicht bietet, weil cargo test Ihren Rust-Code gegen Ihre Rust-Typen ausführt und mit jeder Form problemlos bestehen würde.
Schritt 4: Serde-Ablehnungsfälle abdecken
Der interessante Teil der Rust-JSON-Verarbeitung ist, was Serde mit fehlerhaften Eingaben macht. Standardmäßig gibt Axum eine 422 Unprocessable Entity ohne Details zurück. Erstellen Sie drei Anfragen, die absichtlich das Schema verletzen:
| Anfrage | Body | Erwartet |
|---|---|---|
create-user-missing-email |
{ "name": "Ada" } |
422, Body erwähnt missing field email |
create-user-extra-field |
{ "name": "Ada", "email": "a@b.c", "admin": true } |
200 wenn #[serde(deny_unknown_fields)] nicht vorhanden ist; 422 sonst |
create-user-wrong-type |
{ "name": 1, "email": "a@b.c" } |
422, erwähnt invalid type: integer |
Bestätigen Sie jeden Statuscode in den Tests. Dies ist der günstigste Weg, Ihre tatsächliche Validierungsrichtlinie zu dokumentieren. Wenn Sie später deny_unknown_fields aktivieren, wird der zweite Test rot und zeigt Ihnen an, dass sich der öffentliche Vertrag geändert hat.
Schritt 5: JWT-geschützte Routen testen
Die meisten Rust-APIs in Produktion verbergen Handler hinter einer Authentifizierungs-Middleware. Der axum-extra JWT-Extraktor von Axum ist das gängige Muster:
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() }))
}
In Apidog müssen Sie nicht bei jedem Testlauf ein JWT manuell erstellen. Erstellen Sie ein Pre-Request-Skript im Ordner:
const jwt = require("jsonwebtoken");
const token = jwt.sign(
{ sub: 1, exp: Math.floor(Date.now() / 1000) + 3600 },
"secret"
);
pm.environment.set("token", token);
Öffnen Sie die Ordnereinstellungen, setzen Sie Auth auf Bearer Token, Wert {{token}}. Jede Anfrage im Ordner signiert und präsentiert nun ein neues JWT. Fehler durch veraltete Tokens verschwinden aus Ihren Testläufen. Für eine tiefere Betrachtung der Zusicherungsseite siehe wie man die JWT-Authentifizierung in APIs testet.
Schritt 6: Streaming und Server-Sent Events testen
Rust Web-Frameworks verfügen über erstklassiges Streaming. Die Sse-Antwort von Axum umschließt einen futures::Stream und sendet text/event-stream-Chunks. Das Übertragungsformat ist data: { ... }\n\n pro Frame, beendet durch das Schließen der Verbindung oder ein explizites Done-Ereignis.
Eine Anfrage, die dies konsumiert, sieht aus wie jede andere GET-Anfrage, aber das Antwortpanel in Apidog wechselt in den Streaming-Modus, wenn der Content-Type text/event-stream ist. Sie sehen jeden Frame, sobald er ankommt, mit Zeitstempeln. Das ist die Ansicht, die Sie benötigen, wenn Sie ein Backpressure-Problem oder ein fehlendes Flush debuggen.
Was zu bestätigen ist:
- Der erste Chunk kommt innerhalb der von Ihnen beworbenen SLA an. Apidog zeigt die Latenz pro Chunk im Streaming-Panel an.
- Ein bestimmter Ereignisname wird vor dem Schließen der Verbindung ausgelöst (z.B.
event: done). - Die gesamte Stream-Dauer ist begrenzt. Ein Handler, der vergisst, aus einem
while let Some(event) = stream.next().awaitauszubrechen, streamt ewig; Apidog zeigt dies an und Sie können ein hartes Timeout in den Anforderungseinstellungen festlegen, um den Test fehlschlagen zu lassen.
Wenn Ihr Endpunkt WebSockets anstelle von SSE verwendet, verfügt Apidog über einen separaten WebSocket-Anfragetyp. Das Muster ist dasselbe: Bauen Sie die Verbindung einmal auf, speichern Sie die Nachrichtenfolge, bestätigen Sie die Antworten.
Schritt 7: Die Rust-API für parallele Frontend-Entwicklung mocken
Das Frontend wird selten durch Rust-Kompilierungszeiten blockiert. Es wird durch Handler blockiert, die noch nicht existieren. Apidog-Mocks ermöglichen es Ihnen, eine stabile URL zu veröffentlichen, die den Vertrag zurückgibt, auf den Sie und das Frontend sich geeinigt haben, bevor der Handler ausgeliefert wird.
Rechtsklicken Sie auf create-user, wählen Sie Smart Mock und aktivieren Sie es. Apidog liefert nun eine synthetische User-Antwort unter https://mock.apidog.com/m1/<projectId>/users. Der Mock-Body entspricht Ihrem gespeicherten Beispiel. Die Mock-URL akzeptiert dieselbe Body-Form, sodass das Frontend per POST darauf zugreifen kann, als wäre es der echte Rust-Server.
Für dynamische Mocks wechseln Sie zu Advanced Mock und schreiben ein Skript:
return {
id: Math.floor(Math.random() * 10000),
name: body.name,
email: body.email,
createdAt: new Date().toISOString()
};
Dieser Mock antwortet auf alles, was das Frontend sendet, mit einer generierten id und einem Zeitstempel. Wenn der Rust-Handler bereit ist, ändert das Frontend seine Basis-URL zurück auf http://localhost:3000 und nichts anderes ändert sich. Weitere Informationen zu diesem Muster finden Sie auch in den Beiträgen des Teams über das Erstellen und Testen einer Spring Boot API und den allgemeinen API-Test-Workflow; dieselbe Idee, unterschiedliche Laufzeitumgebungen.
Schritt 8: Als CI-Testszenario speichern
Apidog-Testszenarien verketten Anfragen mit gemeinsamen Variablen und führen sie headless aus. Erstellen Sie ein Szenario:
health-check, bestätigen Sie200.create-user, bestätigen Sie200, erfassen Siebody.idin einer Variable.create-user-missing-email, bestätigen Sie422.me(mit der JWT-Pre-Request), bestätigen Sie200und dass die zurückgegebeneidmit der erfasstenidübereinstimmt.- SSE-Anfrage, bestätigen Sie, dass der Stream innerhalb von 5 Sekunden abgeschlossen wird.
Exportieren Sie das Szenario als JSON, committen Sie es in Ihr Repository unter tests/apidog/ und rufen Sie es aus CI auf:
- name: Run API contract tests
run: |
cargo build --release
./target/release/myserver &
sleep 2
apidog-cli run tests/apidog/contract.json --env "Rust Local"
Jeder PR, der einen Handler betrifft, wird nun gegen eine laufende Rust-Binärdatei mit der vollständigen Vertragssuite ausgeführt. Wenn eine Serde-Umbenennung, eine Statuscode-Änderung oder eine JWT-Validierungsanpassung die öffentliche Form bricht, fängt CI dies ab, bevor der Merge-Button grün wird.
Schritt 9: OpenAPI aus den gespeicherten Anfragen generieren
Wenn der Anfragensatz stabil ist, öffnen Sie das Exportmenü von Apidog und wählen Sie OpenAPI 3.1. Sie erhalten ein Spezifikationsdokument, das jede gespeicherte Anfrage abdeckt, mit den von Ihnen gesendeten Bodies als Beispiele. Übergeben Sie dies jedem, der einen typisierten Client generiert (TypeScript, Swift, Kotlin, Python), und er erhält einen Vertrag, der dem entspricht, was Ihr Rust-Server heute zurückgibt, und nicht dem, was jemand vor sechs Monaten manuell in eine .yaml-Datei geschrieben hat.
Wenn Sie die Spezifikation in Ihr Rust-Repo einchecken möchten, führen Sie apidog-cli export aus CI aus und schreiben Sie sie in openapi.json. Der nächste cargo build ändert sich nicht, aber jeder Verbraucher Ihrer API erhält die Wahrheit auf der Festplatte.
FAQ
Funktioniert Apidog sowohl mit Axum als auch mit Actix-web? Ja. Apidog spricht HTTP, nicht Rust. Alles, was auf eine Anfrage antwortet (Axum, Actix-web, Rocket, Warp, Poem, Loco), funktioniert auf die gleiche Weise. Die einzige Rust-spezifische Überlegung ist die Bindung an 0.0.0.0 anstelle von 127.0.0.1 für lokale Tests.
Wie teste ich Handler, die in Panik geraten? Führen Sie Ihren Server mit tower-https CatchPanicLayer vor dem Router aus. Die Panik wird zu einer 500 mit einem JSON-Body. Erstellen Sie eine Apidog-Anfrage, die den Panikpfad auslöst und die 500 bestätigt. Wenn Sie Paniken nicht abfangen, bricht die Verbindung ab und Apidog meldet einen Netzwerkfehler, was ebenfalls ein gültiger Vertragstest ist.
Kann ich Apidog gegen eine Rust-Binärdatei in Docker ausführen? Ja. Richten Sie baseUrl auf den freigegebenen Port des Containers und Sie sind fertig. Wenn der Container innerhalb von Docker Compose läuft, geben Sie Ihrem Apidog-Runner dasselbe Netzwerk oder verwenden Sie den gemappten Port des Hosts.
Was ist mit gRPC? Apidog verfügt über einen gRPC-Anfragetyp. Importieren Sie Ihre .proto-Dateien, wählen Sie einen Dienst und eine Methode aus, füllen Sie die Anfragenutzlast aus und senden Sie sie. Das Muster für Authentifizierung, Umgebungen und Testszenarien ist identisch mit REST.
Ersetzt das Testszenario cargo test? Nein. Unit-Tests für Ihren Rust-Code bleiben in Rust. Apidog testet die laufende Oberfläche: den HTTP-Vertrag. Die beiden Schichten fangen unterschiedliche Fehler ab. Ein Unit-Test fängt eine fehlerhafte Funktion ab; ein Apidog-Test fängt eine fehlerhafte Antwortform, einen fehlenden CORS-Header oder einen 400, der zu einem 422 wurde, ab. Sie wollen beides.
Ist Apidog kostenlos für Rust Open-Source-Projekte? Ja. Der Apidog-Client ist für Einzelpersonen und kleine Teams kostenlos. Testszenarien, Mocks und der OpenAPI-Export sind Teil des kostenlosen Tarifs. Wenn Sie eine öffentliche Rust-API pflegen, können Sie die Projektdatei in Ihrem Repo bereitstellen, sodass jeder, der klont, die Testsuite erhält.
Zusammenfassung
Rust-APIs verdienen einen Feedback-Loop, der nicht auf den Compiler wartet. Eine Anfragensammlung in Apidog bietet Ihnen diesen Loop: echtes HTTP, echte Zusicherungen, echte Mocks für das Frontend und ein CI-Szenario, das gegen die laufende Binärdatei ausgeführt wird. Erstellen Sie die oben genannten Anfragen einmal, und jede zukünftige Änderung an Ihrem Axum- oder Actix-Handler wird zu einem kontrollierten Testlauf anstelle einer Laufzeitüberraschung.
Laden Sie Apidog herunter und richten Sie es auf Ihren Rust-Server. Die Einrichtung dauert weniger als zehn Minuten. Der Vorteil ist ein Vertrag, den Sie kontrollieren, entkoppelt von cargo, und ein Frontend-Team, das nicht mehr fragt, wann der Handler fertig ist.
