An error type that responds in Rust
Implement IntoResponse for your error and handlers can use the ? operator.
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::{routing::get, Json, Router};
use serde_json::json;
enum ApiError {
NotFound(String),
Invalid { field: &'static str },
}
impl IntoResponse for ApiError {
fn into_response(self) -> Response {
let (status, message) = match self {
ApiError::NotFound(what) => {
(StatusCode::NOT_FOUND, format!("no such {what}"))
}
ApiError::Invalid { field } => (
StatusCode::UNPROCESSABLE_ENTITY,
format!("{field} is invalid"),
),
};
(status, Json(json!({"error": message}))).into_response()
}
}
async fn tour() -> Result<String, ApiError> {
Err(ApiError::NotFound("tour".to_string()))
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/tours/none", get(tour));
let listener = tokio::net::TcpListener::bind("127.0.0.1:8080")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
How it works
- Each variant maps to a status code and a message.
IntoResponseis what makes it returnable.- Handlers then read like ordinary fallible functions.
Keywords and builtins used here
ApiErrorErrResponseResultStringasyncawaitenumfnforimplinto_responseletmainmatchmessageselfstaticstrtouruse
The run, in numbers
- Lines
- 37
- Characters to type
- 872
- Tokens
- 247
- Three-star pace
- 110 tpm
At the three-star pace of 110 tokens a minute, this run takes about 135 seconds.
Step 2 of 3 in Responses & middleware, step 7 of 9 in Web services with axum.