Rust Axum 웹서버
CRUD 기능, JSON 처리, 그리고 체계적인 에러 처리를 포함한 Axum 웹 프레임워크 기반의 서버 템플릿입니다.
use axum::{
extract::{Path, State},
http::StatusCode,
response::{IntoResponse, Response},
routing::{get, post},
Json, Router,
};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, RwLock};
use tower_http::trace::TraceLayer;
#[derive(Debug, Serialize, Deserialize, Clone)]
struct User {
id: u64,
username: String,
email: String,
}
#[derive(Deserialize)]
struct CreateUser {
username: String,
email: String,
}
struct AppState {
users: RwLock<Vec<User>>,
}
enum AppError {
UserNotFound(u64),
Internal(String),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match self {
AppError::UserNotFound(id) => (StatusCode::NOT_FOUND, format!("User {} not found", id)),
AppError::Internal(err) => (StatusCode::INTERNAL_SERVER_ERROR, err),
};
(status, Json(serde_json::json!({ "error": message }))).into_response()
}
}
async fn get_users(State(state): State<Arc<AppState>>) -> impl IntoResponse {
let users = state.users.read().unwrap();
Json(users.clone())
}
async fn create_user(
State(state): State<Arc<AppState>>,
Json(payload): Json<CreateUser>,
) -> impl IntoResponse {
let mut users = state.users.write().unwrap();
let id = users.len() as u64 + 1;
let user = User {
id,
username: payload.username,
email: payload.email,
};
users.push(user.clone());
(StatusCode::CREATED, Json(user))
}
async fn get_user(
Path(id): Path<u64>,
State(state): State<Arc<AppState>>,
) -> Result<impl IntoResponse, AppError> {
let users = state.users.read().unwrap();
let user = users.iter().find(|u| u.id == id).cloned();
match user {
Some(user) => Ok(Json(user)),
None => Err(AppError::UserNotFound(id)),
}
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let state = Arc::new(AppState {
users: RwLock::new(vec![]),
});
let app = Router::new()
.route("/users", get(get_users).post(create_user))
.route("/users/:id", get(get_user))
.layer(TraceLayer::new_for_http())
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
println!("listening on {}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
}