mini-serve 0.6.0

An HTTP server: trie router, middleware, CORS, optional TLS. Built on hyper + tokio.
Documentation
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")
	);
}