Modelling Meetup
In this example we’ll try to implement the routing of Meetuphttps://www.meetup.com/.
[package]
name = "versioning"
version = "0.1.0"
edition = "2024"
publish = false
[dependencies]
axum = "0.8.8"
mime = "0.3.17"
serde = { version = "1.0.228", features = ["derive"] }
tokio = { version = "1.50.0", features = ["full"] }
tracing = "0.1.44"
tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }
[dev-dependencies]
headers = "0.4.1"
http-body-util = "0.1.3"
tower = { version = "0.5.3", features = ["util"] }
Code
use axum::{Router, extract::Path, response::Html, routing::get};
// Meetup: https://www.meetup.com/ redirects to Meetup Home: https://www.meetup.com/home/
// About: https://www.meetup.com/code-mavens/
// Events: https://www.meetup.com/code-mavens/events/
// Members: https://www.meetup.com/code-mavens/members/
// Photos: https://www.meetup.com/code-mavens/photos/
// Discussions: https://www.meetup.com/code-mavens/discussions/
//
// Calendar: https://www.meetup.com/code-mavens/events/calendar/
// Upcoming events: https://www.meetup.com/code-mavens/events/?type=upcoming (the same as without
// this type)
// Past events: https://www.meetup.com/code-mavens/events/?type=past
// Event drafts: https://www.meetup.com/code-mavens/events/?type=draft
// this does not show any event: https://www.meetup.com/code-mavens/events/?type=qqrq
// Event: https://www.meetup.com/code-mavens/events/313944233/?eventOrigin=group_events_list
async fn main_page() -> Html<&'static str> {
Html(
r#"
<h1>Meetup</h1>
<a href="/code-mavens/">About</a><br>
<a href="/code-mavens/events/">Events</a><br>
<a href="/code-mavens/members/">Members</a><br>
<a href="/code-mavens/events/1234">Event ID 1234</a><br>
"#,
)
}
//async fn handle_api(version: Version) -> Html<String> {
// Html(format!("received request with version {version:?}"))
//}
//
async fn handle_about(Path(group): Path<String>) -> Html<String> {
Html(format!("<h1>About {group}</h1>"))
}
async fn handle_area(Path((group, area)): Path<(String, String)>) -> Html<String> {
// Limite area to certain values, e.g. events
Html(format!("<h1>{group} {area}</h1>"))
}
fn create_router() -> Router {
Router::new()
.route("/", get(main_page))
.route("/{group}/", get(handle_about))
.route("/{group}/{area}", get(handle_area))
}
#[tokio::main]
async fn main() {
let app = create_router();
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000")
.await
.unwrap();
println!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}
#[cfg(test)]
mod tests;
Tests
#![allow(unused)]
fn main() {
use axum::{body::Body, http::Request, http::StatusCode};
use http_body_util::BodyExt;
use tower::ServiceExt;
use super::*;
#[tokio::test]
async fn test_main_page() {
check_page("/", "<h1>Meetup</h1>").await;
}
#[tokio::test]
async fn test_about_page() {
check_page("/code-mavens/", "<h1>About code-mavens</h1>").await;
check_page("/python-mavens/", "<h1>About python-mavens</h1>").await;
check_page("/rust-mavens/", "<h1>About rust-mavens</h1>").await;
}
#[tokio::test]
async fn test_events_page() {
check_page("/code-mavens/events", "<h1>code-mavens events</h1>").await;
}
// #[tokio::test]
// async fn test_events_page() {
// check_page("/code-mavens/events/", "<h1>code-mavens events</h1>").await;
// }
async fn check_page(uri: &str, expected: &str) {
let response = create_router()
.oneshot(Request::builder().uri(uri).body(Body::empty()).unwrap())
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body();
let bytes = body.collect().await.unwrap().to_bytes();
let html = String::from_utf8(bytes.to_vec()).unwrap();
assert!(html.contains(expected));
}
}