use hyper::StatusCode;
use mini_serve::{RouteBuilder, handler, path_params};
use serde::Deserialize;
#[derive(Deserialize)]
struct ItemParams {
id: u64,
}
#[tokio::test]
async fn typed_path_param_extracts_parsed_numeric_value() {
let app = RouteBuilder::stateless()
.get("/items/:id", handler(|req, _state| async move {
let params: ItemParams = path_params(&req)?;
mini_serve::json(StatusCode::OK, &serde_json::json!({"id": params.id}))
}))
.seal();
let port = app.bind_ephemeral().await.expect("failed to bind");
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
let resp = reqwest::get(&format!("http://127.0.0.1:{}/items/42", port))
.await
.expect("request failed");
assert_eq!(resp.status(), StatusCode::OK);
let body: serde_json::Value = resp.json().await.expect("failed to parse json");
assert_eq!(body.get("id").and_then(|v| v.as_u64()), Some(42));
}
#[tokio::test]
async fn unparseable_path_param_returns_400_with_documented_message() {
let app = RouteBuilder::stateless()
.get("/items/:id", handler(|req, _state| async move {
let params: ItemParams = path_params(&req)?;
mini_serve::json(StatusCode::OK, &serde_json::json!({"id": params.id}))
}))
.seal();
let port = app.bind_ephemeral().await.expect("failed to bind");
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
let resp = reqwest::get(&format!("http://127.0.0.1:{}/items/not-a-number", port))
.await
.expect("request failed");
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
let body: serde_json::Value = resp.json().await.expect("failed to parse json");
assert_eq!(
body.get("message").and_then(|v| v.as_str()),
Some("invalid path parameters")
);
}