com um clique
axum
Rust Axum 웹 프레임워크 핵심 패턴 - 라우팅, 상태 공유, 추출자, 에러 핸들링, 미들웨어
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Menu
Rust Axum 웹 프레임워크 핵심 패턴 - 라우팅, 상태 공유, 추출자, 에러 핸들링, 미들웨어
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Baseado na classificação ocupacional SOC
Spring Security 5.5.x + jjwt 0.10.7 레거시 JWT 인증 - WebSecurityConfigurerAdapter, OncePerRequestFilter, javax.servlet 환경
Spring Boot 3.x + Spring Security 6.x + jjwt 0.12.x 기반 모던 JWT 인증 패턴. SecurityFilterChain Bean, 람다 DSL, jakarta.servlet, Virtual Threads 적용
Unity 6 LTS 2D 모바일 게임용 uGUI 시스템 전문 스킬. Canvas/RectTransform/TextMeshPro, 모바일 UI 패턴(팝업·무한 스크롤·광고·IAP), 성능 최적화, UI Toolkit과의 선택 기준 포함.
아크라시아(akrasia, 자제력 없음) 학술 논쟁의 핵심 구도와 주요 연구자·문헌을 빠르게 파악할 수 있는 도메인 지식 스킬. 도덕윤리교육 전공 대학원생(석/박사)이 학위논문·KCI 투고·세미나 준비 시 고대–현대–한국 학계–도덕심리학 흐름을 한 번에 짚도록 구성. <example>사용자: "아리스토텔레스의 propeteia와 astheneia 구분을 인용하려는데 출처를 알려줘"</example> <example>사용자: "데이비슨이 의지박약을 어떻게 가능하다고 봤는지 핵심 논증을 정리해줘"</example> <example>사용자: "한국 도덕교육 학계에서 아크라시아 다룬 논문 있어?"</example>
아리스토텔레스 『니코마코스 윤리학』에서 akrasia(자제력없음)와 akolasia(무절제)의 5축 차이를 정밀하게 정리한 학위논문 자료 스킬. NE VII.4 1147b20-1148b14, VII.8 1150b29-1151a28, III.10-12 1117b23-1119b18 절별 분해와 표준 학자 해석(Bostock, Broadie-Rowe, Pakaluk, Hursthouse, Charles 등)을 포함. 도덕교육 적용을 위한 두 상태 차이의 함의 및 한국어 번역어 처리 권장안 제공. <example>사용자: "akrates와 akolastos를 prohairesis 측면에서 어떻게 구분해야 하나요?"</example> <example>사용자: "NE VII.4의 ἁπλῶς akrasia가 akolasia와 어떻게 갈라지는지 절별 분해해주세요"</example> <example>사용자: "Hursthouse의 연속체 모델을 도덕교육 적용 절에서 어떻게 활용할 수 있나요?"</example>
한국 위기 대응 자원(자살·자해·정신건강·여성·청소년·노인·다문화) 핫라인과 앱·챗봇 안전 가드 응답 패턴 종합. 꿈 해몽·정신건강 앱 등 자가 진단/감정 콘텐츠 도메인에서 위험 신호 포착 시 안전한 자원 안내 문구를 작성할 때 참조. <example>사용자: "꿈 해몽 앱에 위기 안내 문구를 어떻게 넣을까?"</example> <example>사용자: "한국에서 자살예방 핫라인 번호가 어떻게 바뀌었지?"</example> <example>사용자: "정신건강 챗봇 안전 가드 응답 템플릿을 짜줘"</example>
| name | axum |
| description | Rust Axum 웹 프레임워크 핵심 패턴 - 라우팅, 상태 공유, 추출자, 에러 핸들링, 미들웨어 |
소스: https://docs.rs/axum/latest/axum/ | https://github.com/tokio-rs/axum 검증일: 2026-06-20
주의: 이 문서는 axum 0.8.x 기준으로 작성되었습니다. 0.7에서 0.8로의 마이그레이션 시 Breaking Change가 있으므로 공식 changelog를 반드시 확인하세요.
# Cargo.toml
[dependencies]
axum = "0.8"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tower = "0.5"
tower-http = { version = "0.6", features = ["cors", "trace"] }
use axum::Router;
use tokio::net::TcpListener;
#[tokio::main]
async fn main() {
let app = Router::new();
let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
주의: axum 0.7부터
axum::Server를 사용할 수 없습니다 (hyper 1.0 의존으로 소멸).tokio::net::TcpListener+axum::serve를 사용합니다.
use axum::{
routing::{get, post, put, delete},
Router,
};
let app = Router::new()
.route("/", get(root_handler))
.route("/users", get(list_users).post(create_user))
.route("/users/{id}", get(get_user).put(update_user).delete(delete_user));
주의: axum 0.8부터 경로 파라미터 문법이
:id에서{id}로 변경되었습니다.
핸들러는 추출자를 인자로 받고 IntoResponse를 반환하는 async 함수입니다.
use axum::response::IntoResponse;
use axum::http::StatusCode;
// 단순 문자열 반환
async fn root_handler() -> &'static str {
"Hello, World!"
}
// StatusCode + 본문
async fn not_found() -> (StatusCode, &'static str) {
(StatusCode::NOT_FOUND, "Not Found")
}
// impl IntoResponse
async fn health_check() -> impl IntoResponse {
(StatusCode::OK, "OK")
}
let api_routes = Router::new()
.route("/users", get(list_users))
.route("/posts", get(list_posts));
let app = Router::new()
.nest("/api/v1", api_routes);
// /api/v1/users, /api/v1/posts 로 접근
let app = Router::new()
.route("/", get(root_handler))
.fallback(fallback_handler);
async fn fallback_handler() -> (StatusCode, &'static str) {
(StatusCode::NOT_FOUND, "Route not found")
}
추출자는 핸들러 함수의 인자로 사용됩니다. 마지막 인자만 요청 본문을 소비할 수 있습니다.
use axum::extract::Path;
// 단일 파라미터
async fn get_user(Path(id): Path<u64>) -> String {
format!("User: {id}")
}
// 복수 파라미터
async fn get_post(Path((user_id, post_id)): Path<(u64, u64)>) -> String {
format!("User {user_id}, Post {post_id}")
}
// 구조체로 역직렬화
#[derive(Deserialize)]
struct PostParams {
user_id: u64,
post_id: u64,
}
async fn get_post_v2(Path(params): Path<PostParams>) -> String {
format!("User {}, Post {}", params.user_id, params.post_id)
}
use axum::extract::Query;
use serde::Deserialize;
#[derive(Deserialize)]
struct Pagination {
page: Option<u32>,
per_page: Option<u32>,
}
async fn list_users(Query(pagination): Query<Pagination>) -> String {
let page = pagination.page.unwrap_or(1);
let per_page = pagination.per_page.unwrap_or(20);
format!("Page {page}, per_page {per_page}")
}
use axum::Json;
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
struct CreateUser {
username: String,
email: String,
}
#[derive(Serialize)]
struct User {
id: u64,
username: String,
}
async fn create_user(Json(payload): Json<CreateUser>) -> (StatusCode, Json<User>) {
let user = User {
id: 1,
username: payload.username,
};
(StatusCode::CREATED, Json(user))
}
use axum::http::HeaderMap;
use axum_extra::TypedHeader;
use axum_extra::headers::Authorization;
use axum_extra::headers::authorization::Bearer;
// HeaderMap으로 직접 접근
async fn with_headers(headers: HeaderMap) -> String {
let user_agent = headers
.get("user-agent")
.and_then(|v| v.to_str().ok())
.unwrap_or("unknown");
format!("User-Agent: {user_agent}")
}
// TypedHeader (axum-extra 필요)
async fn with_auth(
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
) -> String {
format!("Token: {}", auth.token())
}
주의:
TypedHeader는axum-extra크레이트에 있으며,typed-headerfeature를 활성화해야 합니다. (axum-extra = { version = "0.9", features = ["typed-header"] })
// 본문을 소비하는 추출자(Json, String, Bytes)는 반드시 마지막 인자
async fn handler(
Path(id): Path<u64>, // 본문 비소비 - 순서 자유
Query(params): Query<Params>, // 본문 비소비 - 순서 자유
headers: HeaderMap, // 본문 비소비 - 순서 자유
Json(body): Json<CreateUser>, // 본문 소비 - 반드시 마지막
) -> impl IntoResponse {
// ...
}
use axum::extract::State;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Clone)]
struct AppState {
db_pool: sqlx::PgPool,
// 또는 가변 상태가 필요한 경우:
counter: Arc<RwLock<u64>>,
}
async fn handler(State(state): State<AppState>) -> String {
let count = state.counter.read().await;
format!("Count: {count}")
}
#[tokio::main]
async fn main() {
let state = AppState {
db_pool: /* ... */,
counter: Arc::new(RwLock::new(0)),
};
let app = Router::new()
.route("/", get(handler))
.with_state(state);
// ...
}
State에 전달하는 타입은 Clone을 구현해야 합니다. 큰 데이터는 Arc로 감싸세요.
// 방법 1: 구조체 전체를 Arc로 감싸기
type SharedState = Arc<InnerState>;
struct InnerState {
db_pool: sqlx::PgPool,
}
let state = Arc::new(InnerState { /* ... */ });
let app = Router::new()
.route("/", get(handler))
.with_state(state);
use axum::Extension;
// State 대신 Extension으로도 공유 가능 (0.6 이전 방식)
// State 추출자를 사용하는 것이 공식 권장됨
let app = Router::new()
.route("/", get(handler))
.layer(Extension(shared_data));
async fn handler(Extension(data): Extension<SharedData>) -> String {
// ...
}
주의: Extension은 컴파일 타임에 타입 검사가 되지 않아 런타임 에러 가능성이 있습니다. axum 0.6부터 State 추출자가 도입되었으며 공식적으로 State 사용이 권장됩니다.
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
enum AppError {
NotFound,
Internal(String),
BadRequest(String),
}
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match self {
AppError::NotFound => (StatusCode::NOT_FOUND, "Not Found".to_string()),
AppError::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
};
(status, message).into_response()
}
}
async fn get_user(Path(id): Path<u64>) -> Result<Json<User>, AppError> {
let user = find_user(id).ok_or(AppError::NotFound)?;
Ok(Json(user))
}
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
struct AppError(anyhow::Error);
impl IntoResponse for AppError {
fn into_response(self) -> Response {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Something went wrong: {}", self.0),
)
.into_response()
}
}
// anyhow::Error -> AppError 자동 변환
impl<E> From<E> for AppError
where
E: Into<anyhow::Error>,
{
fn from(err: E) -> Self {
Self(err.into())
}
}
// 핸들러에서 ? 연산자 자유롭게 사용 가능
async fn handler() -> Result<String, AppError> {
let data = std::fs::read_to_string("file.txt")?;
Ok(data)
}
use axum::extract::rejection::JsonRejection;
// Json 추출 실패 시 커스텀 에러 반환
async fn create_user(
payload: Result<Json<CreateUser>, JsonRejection>,
) -> Result<Json<User>, AppError> {
let Json(payload) = payload.map_err(|e| AppError::BadRequest(e.to_string()))?;
// ...
}
상세 레퍼런스 (예제·고급 패턴·흔한 실수) →
references/REFERENCE.md