use std::{ collections::HashMap, sync::{Arc, RwLock}, }; use axum::{ extract::{Path, State}, http::StatusCode, response::IntoResponse, routing::get, Json, Router, }; use jsend::JSendResponse; use serde::{Deserialize, Serialize}; use serde_json::json; use uuid::Uuid; #[derive(Serialize, Debug, Clone)] struct Post { id: Uuid, title: String, body: String, } #[derive(Debug, Deserialize, Clone)] struct CreatePost { title: String, body: String, } type Db = Arc>>; #[tokio::main] async fn main() { let db = Db::default(); let post = Post { id: Uuid::new_v4(), title: "Blog Post Title".to_string(), body: "Blog post body".to_string(), }; db.write().unwrap().insert(post.id, post); let app = Router::new() .route("/posts", get(list_posts).post(create_post)) .route("/posts/:id", get(get_post_by_id).delete(delete_post_by_id)) .with_state(db); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); } async fn list_posts(State(db): State) -> impl IntoResponse { let mut posts: Vec = vec![]; for (_id, post) in db.read().unwrap().clone() { posts.push(post); } Json(JSendResponse::success(Some(json!({"posts": posts})))) } async fn create_post(State(db): State, Json(input): Json) -> impl IntoResponse { let post = Post { id: Uuid::new_v4(), title: input.title, body: input.body, }; let id = post.id; db.write().unwrap().insert(post.id, post); Json(JSendResponse::success(Some(json!({"id": id})))) } async fn get_post_by_id(Path(id): Path, State(db): State) -> impl IntoResponse { let db = db.read().unwrap(); let post = db.get(&id); match post { Some(post) => Json(JSendResponse::success(Some(json!({"post": post})))).into_response(), None => ( StatusCode::NOT_FOUND, Json(JSendResponse::fail(json!({"id": "not found"}))), ) .into_response(), } } async fn delete_post_by_id(Path(id): Path, State(db): State) -> impl IntoResponse { let mut db = db.write().unwrap(); db.remove(&id).unwrap(); Json(JSendResponse::success(None::<()>)) }