That returns the complete race state, which, for now, is only the name
of the race.
New rust features seen for the first time as of this commit:
* std::sync::Arc for atomically-reference-counted pointers (with
thread-safe reference counting as you would expect from the name).
* "crate::" in 'use' paths to reference the root of the current project
* impl: For creating functions associated with a struct
* Destructuring in a function parameter: State(state): State<Arc<AppState>>
* clone() to carefully give the RaceResponse a string it
owns. (Note: The rust compiler wouldn't even accept the code
without this clone(): "cannot move out of an `Arc`)
--- /dev/null
+use axum::Json;
+use axum::extract::State;
+use serde::Serialize;
+use std::sync::Arc;
+
+use crate::state::AppState;
+
+#[derive(Serialize)]
+pub struct RaceResponse {
+ pub name: String,
+}
+
+pub async fn get_race(State(state): State<Arc<AppState>>) -> Json<RaceResponse> {
+ Json(RaceResponse {
+ name: state.race_name.clone(),
+ })
+}
mod config;
+mod handlers;
+mod state;
+use axum::Router;
+use axum::routing::get;
use std::error::Error;
#[tokio::main]
eprintln!("Race: {}", config.name);
+ let state = state::AppState::new(config);
+
+ // Public read routes
+ let read_routes = Router::new().route("/race", get(handlers::get_race));
+
let bind = "0.0.0.0:3000";
eprintln!("Listening on {}", bind);
let listener = tokio::net::TcpListener::bind(&bind).await?;
- let app = axum::Router::new();
+ let app = Router::new().merge(read_routes).with_state(state);
axum::serve(listener, app)
.with_graceful_shutdown(async move {
--- /dev/null
+use std::sync::Arc;
+
+use crate::config::ConfigFile;
+
+pub struct AppState {
+ pub race_name: String,
+}
+
+impl AppState {
+ pub fn new(config: ConfigFile) -> Arc<Self> {
+ Arc::new(Self {
+ race_name: config.name,
+ })
+ }
+}