feat server add user api
This commit is contained in:
@@ -5,4 +5,7 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
axum = "0.8.4"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
sqlx = { version = "0.8.6", features = ["mysql", "runtime-tokio"] }
|
||||
tokio = { version = "1.46.1", features = ["net", "rt-multi-thread"] }
|
||||
tracing-subscriber = "0.3.19"
|
||||
|
7
server/sql/user.sql
Normal file
7
server/sql/user.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
CREATE TABLE `users` (
|
||||
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` varchar(100) NOT NULL,
|
||||
`email` varchar(255) NOT NULL,
|
||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
) charset=utf8mb4;
|
@@ -1,4 +1,126 @@
|
||||
fn main() {
|
||||
tracing_subscriber::fmt::init();
|
||||
println!("Hello, world!");
|
||||
use axum::{
|
||||
Router,
|
||||
extract::{Json, Path, Query, State},
|
||||
http::StatusCode,
|
||||
routing::{delete, get, patch, post, put},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::mysql::{MySqlConnectOptions, MySqlPool, MySqlPoolOptions};
|
||||
use sqlx::{ConnectOptions, Connection};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct AppState {
|
||||
db_pool: MySqlPool,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let pool = MySqlPoolOptions::new()
|
||||
.max_connections(20)
|
||||
.min_connections(5)
|
||||
.connect("mysql://tqcq:tqcq@127.0.0.1:3306/tqcq")
|
||||
.await
|
||||
.unwrap();
|
||||
let app_state = AppState { db_pool: pool };
|
||||
|
||||
let app = Router::new()
|
||||
.route("/api/v1/user", put(user_create))
|
||||
.route("/api/v1/user/{user_id}", get(user_get))
|
||||
.route("/api/v1/user/{user_id}", delete(user_delete))
|
||||
.with_state(app_state);
|
||||
|
||||
let listener = tokio::net::TcpListener::bind("0.0.0.0:9000").await.unwrap();
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
||||
#[derive(Serialize, sqlx::FromRow)]
|
||||
struct User {
|
||||
id: u32,
|
||||
name: String,
|
||||
email: String,
|
||||
}
|
||||
impl Default for User {
|
||||
fn default() -> Self {
|
||||
let user = User {
|
||||
id: 0,
|
||||
name: "".to_string(),
|
||||
email: "".to_string(),
|
||||
};
|
||||
user
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct UserCreate {
|
||||
name: String,
|
||||
email: String,
|
||||
}
|
||||
|
||||
async fn user_create(
|
||||
State(state): State<AppState>,
|
||||
Json(payload): Json<UserCreate>,
|
||||
) -> (StatusCode, Json<User>) {
|
||||
// let mut tx = state.db_pool.begin().await.unwrap();
|
||||
let res = sqlx::query("INSERT INTO `users`(name,email) SELECT ?,? WHERE NOT EXISTS (SELECT id FROM `users` WHERE email = ?)")
|
||||
.bind(payload.name.clone())
|
||||
.bind(payload.email.clone())
|
||||
.bind(payload.email.clone())
|
||||
.execute(&state.db_pool)
|
||||
.await;
|
||||
|
||||
if let Ok(res) = res {
|
||||
if res.rows_affected() == 1u64 {
|
||||
let row: (u32,) = sqlx::query_as("SELECT id FROM `users` WHERE email = ?")
|
||||
.bind(payload.email.clone())
|
||||
.fetch_one(&state.db_pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let user = User {
|
||||
id: row.0,
|
||||
name: payload.name,
|
||||
email: payload.email,
|
||||
};
|
||||
return (StatusCode::CREATED, Json(user));
|
||||
} else {
|
||||
println!("Insert Failed.")
|
||||
}
|
||||
} else {
|
||||
let err = res.err();
|
||||
println!("{:#?}", err);
|
||||
}
|
||||
|
||||
return (StatusCode::NOT_FOUND, Json(User::default()));
|
||||
}
|
||||
|
||||
async fn user_get(
|
||||
State(state): State<AppState>,
|
||||
Path(user_id): Path<u32>,
|
||||
) -> (StatusCode, Json<User>) {
|
||||
let user = sqlx::query_as::<_, User>("SELECT id,name,email FROM `users` WHERE id = ?")
|
||||
.bind(user_id)
|
||||
.fetch_one(&state.db_pool)
|
||||
.await;
|
||||
|
||||
if let Ok(user) = user {
|
||||
return (StatusCode::OK, Json(user));
|
||||
} else {
|
||||
return (StatusCode::NOT_FOUND, Json(User::default()));
|
||||
}
|
||||
}
|
||||
|
||||
async fn user_delete(State(state): State<AppState>, Path(user_id): Path<u32>) -> StatusCode {
|
||||
let rows: u64 = sqlx::query("DELETE FROM `users` WHERE id = $1")
|
||||
.bind(user_id)
|
||||
.execute(&state.db_pool)
|
||||
.await
|
||||
.unwrap()
|
||||
.rows_affected();
|
||||
if rows == 1u64 {
|
||||
StatusCode::OK
|
||||
} else {
|
||||
StatusCode::NOT_FOUND
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user