Rust와 Axum을 활용한 웹 백엔드 개발 - Axum 프레임워크 소개
1-1. Axum의 특징과 설치
Axum의 주요 특징
Axum은 Rust로 작성된 경량의 웹 애플리케이션 프레임워크로, Tokio 비동기 런타임을 기반으로 합니다. 주요 특징은 다음과 같습니다:
- 간단한 라우팅: 함수와 경로를 간단하게 매핑하여 핸들러를 정의할 수 있습니다.
- 비동기 지원: Tokio 런타임과 함께 비동기 프로그래밍을 효율적으로 지원합니다.
- 확장성: 다른 라이브러리와의 통합이 용이하며, 필요한 기능을 모듈화하여 사용할 수 있습니다.
- 상태 관리 용이성: 애플리케이션 상태를 쉽게 공유하고 관리할 수 있습니다.
Axum 설치하기
Axum을 사용하려면 Cargo.toml
파일에 의존성을 추가해야 합니다.
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
axum
: 웹 프레임워크tokio
: 비동기 런타임
1-2. 기본 라우팅 설정 및 핸들러 작성
"Hello, World!" 예제
가장 기본적인 Axum 웹 서버를 만들어 보겠습니다.
src/main.rs
:
use axum::{
routing::get,
Router,
};
use std::net::SocketAddr;
#[tokio::main]
async fn main() {
// 라우터 생성: "/" 경로에 대한 요청을 `hello_world` 핸들러에 연결
let app = Router::new().route("/", get(hello_world));
// 서버를 바인딩할 주소 설정
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("서버가 {}에서 실행 중입니다.", addr);
// 서버 실행
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
// 핸들러 함수 정의
async fn hello_world() -> &'static str {
"Hello, World!"
}
실행하기:
cargo run
웹 브라우저에서 http://127.0.0.1:3000/
에 접속하면 "Hello, World!" 메시지를 볼 수 있습니다.
라우팅 설정
다양한 경로와 HTTP 메서드를 설정하여 라우팅을 구성할 수 있습니다.
use axum::routing::{get, post};
let app = Router::new()
.route("/get", get(get_handler))
.route("/post", post(post_handler));
1-3. 요청과 응답 처리 방법
요청 데이터 추출
경로 매개변수 추출
경로에서 변수를 추출하여 핸들러 함수의 매개변수로 사용할 수 있습니다.
use axum::{extract::Path, routing::get, Router};
async fn greet(Path(name): Path<String>) -> String {
format!("Hello, {}!", name)
}
let app = Router::new().route("/greet/:name", get(greet));
예를 들어, /greet/Alice
로 요청하면 "Hello, Alice!"를 반환합니다.
쿼리 문자열 추출
use axum::{extract::Query, routing::get, Router};
use std::collections::HashMap;
async fn query_params(Query(params): Query<HashMap<String, String>>) -> String {
format!("쿼리 파라미터: {:?}", params)
}
let app = Router::new().route("/search", get(query_params));
/search?keyword=rust&sort=asc
로 요청하면 쿼리 파라미터를 추출하여 반환합니다.
JSON 바디 추출
use axum::{extract::Json, routing::post, Router};
use serde::Deserialize;
#[derive(Deserialize)]
struct CreateUser {
username: String,
email: String,
}
async fn create_user(Json(payload): Json<CreateUser>) -> String {
format!("사용자 생성: {} ({})", payload.username, payload.email)
}
let app = Router::new().route("/users", post(create_user));
클라이언트에서 JSON 형식의 데이터를 POST로 전송하면 구조체로 매핑하여 사용할 수 있습니다.
응답 생성
문자열 응답
핸들러 함수에서 String
또는 &'static str
을 반환하여 텍스트 응답을 보낼 수 있습니다.
async fn simple_response() -> &'static str {
"간단한 응답 메시지"
}
JSON 응답
use axum::{response::Json, routing::get, Router};
use serde::Serialize;
#[derive(Serialize)]
struct User {
id: u32,
username: String,
}
async fn get_user() -> Json<User> {
let user = User {
id: 1,
username: "Alice".to_string(),
};
Json(user)
}
let app = Router::new().route("/user", get(get_user));
응답 데이터를 JSON으로 직렬화하여 반환합니다.
1-4. 상태 관리 및 공유 데이터 처리
애플리케이션 상태 공유
애플리케이션에서 공통으로 사용하는 상태를 공유하려면 Extension
을 사용합니다.
use axum::{
extract::Extension,
routing::get,
Router,
};
use std::sync::Arc;
struct AppState {
app_name: String,
}
async fn handler(Extension(state): Extension<Arc<AppState>>) -> String {
format!("앱 이름: {}", state.app_name)
}
#[tokio::main]
async fn main() {
let state = Arc::new(AppState {
app_name: "My Axum App".to_string(),
});
let app = Router::new()
.route("/", get(handler))
.layer(Extension(state));
axum::Server::bind(&"127.0.0.1:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
Arc
를 사용하여 다중 스레드 환경에서 안전하게 상태를 공유합니다.Extension
레이어를 통해 상태를 애플리케이션에 주입합니다.
상태 사용 예시: 카운터 증가
use axum::{
extract::Extension,
routing::get,
Router,
};
use std::sync::{Arc, Mutex};
struct AppState {
counter: Mutex<u32>,
}
async fn increment_counter(Extension(state): Extension<Arc<AppState>>) -> String {
let mut counter = state.counter.lock().unwrap();
*counter += 1;
format!("현재 카운터 값: {}", counter)
}
#[tokio::main]
async fn main() {
let state = Arc::new(AppState {
counter: Mutex::new(0),
});
let app = Router::new()
.route("/count", get(increment_counter))
.layer(Extension(state));
axum::Server::bind(&"127.0.0.1:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
Mutex
를 사용하여 공유 자원의 동시 접근을 제어합니다./count
엔드포인트에 접근할 때마다 카운터가 증가합니다.
결론
Axum은 Rust로 웹 애플리케이션을 개발할 때 간단하면서도 강력한 기능을 제공합니다. 이번 글에서는 Axum의 특징과 설치 방법부터 기본적인 라우팅 설정, 요청과 응답 처리, 그리고 상태 관리 및 공유 데이터 처리까지 살펴보았습니다. 이러한 기본 개념을 바탕으로 더 복잡한 웹 애플리케이션을 구축할 수 있습니다.
연습 과제:
- 추가 엔드포인트 구현하기
- 여러 개의 엔드포인트를 추가하여 다양한 HTTP 메서드와 경로를 연습해보세요.
- 상태를 활용한 간단한 애플리케이션 만들기
- 상태를 사용하여 방문자 수를 추적하거나, 간단한 메모장 기능을 구현해보세요.
- 에러 처리 추가하기
- 요청 처리 중 발생할 수 있는 에러를 적절히 처리하고 사용자에게 의미 있는 응답을 반환하도록 해보세요.
참고 자료
Note: 이 글은 Axum 프레임워크의 기본 사용법을 소개하기 위한 것으로, 더 깊은 이해를 위해서는 공식 문서와 추가 자료를 참고하시기 바랍니다.