axum 핸들러(Handler)와 라우팅¶
개요¶
Rust로 HTTP 서버를 만들 때 "라우트를 어떻게 잡고, 각 요청을 어느 함수로 보낼까"가 첫 관문이에요. axum은 매크로 없이도 직관적인 라우팅 API를 제공하는 HTTP 라우팅·요청 처리 라이브러리입니다. 핸들러라는 비동기 함수가 들어오는 요청을 처리하고, Router가 어떤 경로를 어떤 핸들러로 연결할지 정합니다. axum의 철학은 "지루한 보일러플레이트를 줄이고, tower 미들웨어 생태계를 그대로 활용하게 하자"는 데 있어요.
핵심 개념¶
핸들러는 비동기 함수¶
axum에서 핸들러(handler)는 0개 이상의 추출기(extractor)를 인자로 받고, 응답으로 변환할 수 있는 값을 반환하는 비동기 함수예요. 핸들러가 바로 애플리케이션 로직이 살아 있는 곳이고, axum 애플리케이션은 핸들러들을 라우팅으로 연결해 만듭니다.
use axum::{routing::get, Router};
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(|| async { "Hello, World!" }));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
#[tokio::main]을 쓰려면 tokio의 macros와 rt-multi-thread 기능(full이면 모두)을 켜야 해요.
Handler 트레이트와 제약¶
함수가 핸들러로 쓰이려면 Handler 트레이트를 구현해야 합니다. axum은 다음 조건을 만족하는 함수에 대해 통합 구현(blanket impl)을 제공해요.
async fn이다.- 최대 16개, 모두
Send인 인자를 받는다. - 마지막 인자를 제외한 나머지는
FromRequestParts를 구현한다. - 마지막 인자는
FromRequest를 구현한다. IntoResponse를 구현하는 값을 반환한다.- 반환하는 future가
Send다.
함수가 이 조건을 만족하지 않을 때 Rust는 오류 메시지가 아주 친절하진 않아요. 이때 axum-macros 크레이트의 debug_handler 프로시저 매크로로 원인을 좀 더 명확하게 볼 수 있습니다.
라우팅¶
Router가 어떤 경로를 어떤 서비스로 보낼지 정합니다. 한 경로에 메서드별 핸들러를 여러 개 붙일 수도 있어요.
let app = Router::new()
.route("/", get(root))
.route("/foo", get(get_foo).post(post_foo))
.route("/foo/bar", get(foo_bar));
경로 파라미터는 {user_id}처럼 중괄호로 표기합니다(예: /path/{user_id}).
tower 미들웨어 활용¶
axum은 자체 미들웨어 시스템이 없고 tower::Service를 사용해요. 그래서 타임아웃, 트레이싱, 압축, 인증 등의 미들웨어를 거의 공짜로 얻을 수 있고, hyper나 tonic으로 만든 애플리케이션과도 미들웨어를 공유할 수 있습니다. axum은 tokio와 hyper 위에서 동작하도록 설계되었어요.
실제 적용 (데이터스케쳐스 관점)¶
axum은 Rust가 필요한 백엔드에서 요청 처리를 구조화하는 데 쓰여요.
- 매크로 없는 라우팅 —
Router와 핸들러 함수로 직관적으로 라우트를 잡아요. - tower 생태계 활용 — 기존
tower-http미들웨어(압축, 트레이싱, 타임아웃)를 붙여 운영 요구를 해결합니다. - 에러 처리 모델 —
IntoResponse기반의 단순하고 예측 가능한 에러 처리를 활용해요.
더 알아보기¶
- 공식 문서 (1차): axum::handler · axum overview
- 인접 챕터: 추출기(Extractors)
- 상위 문서: axum