콘텐츠로 이동

axum 추출기(Extractors)

개요

HTTP 요청에서 경로 파라미터, 쿼리, 본문, 헤더 같은 것을 꺼내는 코드는 손으로 쓰면 반복적이고 실수하기 쉬워요. axum은 추출기(extractor)라는 개념으로 이 반복을 제거합니다. 추출기는 FromRequestFromRequestParts를 구현하는 타입인데, 핸들러 함수의 인자로 넣으면 axum이 알아서 요청에서 필요한 부분을 꺼내 전달해 줍니다. 핸들러는 선언적으로 "이것들이 필요해"라고 말만 하면 되는 거죠.

핵심 개념

추출기는 요청을 분해하는 타입

추출기는 요청에서 핸들러가 필요한 부분을 분해하는 타입이에요. 예를 들어 Json은 요청 본문을 소비해서 JSON으로 역직렬화하는 추출기입니다.

use axum::extract::Json;
use serde::Deserialize;

#[derive(Deserialize)]
struct CreateUser {
    email: String,
    password: String,
}

async fn create_user(Json(payload): Json<CreateUser>) {
    // ...
}

자주 쓰는 추출기

axum은 다양한 내장 추출기를 제공해요.

  • Path — 경로 파라미터를 역직렬화한다. 예: Path(user_id): Path<u32>.
  • Query — 쿼리 파라미터를 역직렬화한다. 예: Query(params): Query<HashMap<String, String>>.
  • HeaderMap — 모든 헤더를 제공한다.
  • String — 요청 본문을 소비하고 UTF-8인지 확인한다.
  • Bytes — 원본 요청 본문을 그대로 준다.
  • Json — 요청 본문을 JSON으로 파싱한다.
  • Request — 최대 제어를 위해 요청 전체를 준다.
  • Extension — 요청 확장(extensions)에서 데이터를 꺼낸다. 상태(state)를 핸들러와 공유할 때 자주 써요.
async fn path(Path(user_id): Path<u32>) {}
async fn query(Query(params): Query<HashMap<String, String>>) {}
async fn json(Json(payload): Json<Value>) {}

여러 추출기 조합

추출기는 여러 개를 함께 쓸 수 있어요. 예를 들어 경로 파라미터와 쿼리를 동시에 받는 핸들러도 자연스럽게 만들 수 있습니다.

async fn get_user_things(
    Path(user_id): Path<Uuid>,
    Query(pagination): Query<Pagination>,
) {
    // ...
}

추출기 순서와 본문 소비

추출기는 함수 파라미터 순서대로, 왼쪽에서 오른쪽으로 항상 실행돼요. 여기서 중요한 제약이 하나 있어요. 요청 본문은 한 번만 소비할 수 있는 비동기 스트림이라서, 본문을 소비하는 추출기(Json, String, Bytes 등)는 핸들러당 하나만 쓸 수 있습니다. 파라미터로 FromRequestParts(본문을 소비하지 않음)와 FromRequest(본문을 소비함)를 구분해서 아는 게 이 규칙을 이해하는 데 도움이 돼요.

실제 적용 (데이터스케쳐스 관점)

axum 기반 백엔드에서 추출기는 요청 처리를 선언적으로 만들어요.

  • 선언적 요청 분해 — 경로·쿼리·본문을 추출기로 받아 파싱 코드를 줄이고 실수를 방지해요.
  • 상태 공유Extension으로 공유 상태를 핸들러에 주입해 세션·설정을 전달합니다.
  • 타입 안전한 바인딩Json<CreateUser>처럼 역직렬화 대상 타입을 명시해 요청 스키마를 컴파일 타임에 잡아요.

더 알아보기