1use rapid_rs::prelude::*;
6
7#[derive(Serialize, Deserialize, Clone, ToSchema)]
8struct User {
9 id: Uuid,
10 email: String,
11 name: String,
12 created_at: DateTime<Utc>,
13}
14
15#[derive(Deserialize, Validate, ToSchema)]
16struct CreateUserRequest {
17 #[validate(email(message = "Invalid email format"))]
18 email: String,
19
20 #[validate(length(
21 min = 2,
22 max = 100,
23 message = "Name must be between 2 and 100 characters"
24 ))]
25 name: String,
26}
27
28#[derive(Deserialize, Validate, ToSchema)]
29struct UpdateUserRequest {
30 #[validate(length(
31 min = 2,
32 max = 100,
33 message = "Name must be between 2 and 100 characters"
34 ))]
35 name: Option<String>,
36}
37
38use std::collections::HashMap;
40use std::sync::{Arc, Mutex};
41
42type Database = Arc<Mutex<HashMap<Uuid, User>>>;
43
44async fn create_user(
46 State(db): State<Database>,
47 ValidatedJson(payload): ValidatedJson<CreateUserRequest>,
48) -> ApiResult<User> {
49 let user = User {
50 id: Uuid::new_v4(),
51 email: payload.email,
52 name: payload.name,
53 created_at: Utc::now(),
54 };
55
56 db.lock().unwrap().insert(user.id, user.clone());
57
58 Ok(Json(user))
59}
60
61async fn list_users(State(db): State<Database>) -> ApiResult<Vec<User>> {
63 let users: Vec<User> = db.lock().unwrap().values().cloned().collect();
64 Ok(Json(users))
65}
66
67async fn get_user(
69 State(db): State<Database>,
70 Path(id): Path<Uuid>,
71) -> Result<Json<User>, ApiError> {
72 let db = db.lock().unwrap();
73 let user = db
74 .get(&id)
75 .ok_or_else(|| ApiError::NotFound(format!("User with id {} not found", id)))?;
76
77 Ok(Json(user.clone()))
78}
79
80async fn update_user(
82 State(db): State<Database>,
83 Path(id): Path<Uuid>,
84 ValidatedJson(payload): ValidatedJson<UpdateUserRequest>,
85) -> Result<Json<User>, ApiError> {
86 let mut db = db.lock().unwrap();
87 let user = db
88 .get_mut(&id)
89 .ok_or_else(|| ApiError::NotFound(format!("User with id {} not found", id)))?;
90
91 if let Some(name) = payload.name {
92 user.name = name;
93 }
94
95 Ok(Json(user.clone()))
96}
97
98async fn delete_user(
100 State(db): State<Database>,
101 Path(id): Path<Uuid>,
102) -> Result<Json<User>, ApiError> {
103 let mut db = db.lock().unwrap();
104 let user = db
105 .remove(&id)
106 .ok_or_else(|| ApiError::NotFound(format!("User with id {} not found", id)))?;
107
108 Ok(Json(user))
109}
110
111fn user_routes() -> Router<Database> {
112 Router::new()
113 .route("/users", post(create_user))
114 .route("/users", get(list_users))
115 .route("/users/:id", get(get_user))
116 .route("/users/:id", patch(update_user))
117 .route("/users/:id", delete(delete_user))
118}
119
120#[tokio::main]
121async fn main() {
122 let db: Database = Arc::new(Mutex::new(HashMap::new()));
124
125 App::new()
127 .auto_configure()
128 .mount(user_routes().with_state(db))
129 .run()
130 .await
131 .unwrap();
132}