axumのルーティングを整理して別ファイルに分ける方法

オフ 投稿者: sesera

こんにちは!今回は、axumでのルーティングをきれいに整理する方法を紹介します。

目次

よくある一括ルーティングの例

まずは、よくあるmain.rsにすべてのルートを書いているパターンを見てみましょう:

use axum::{
    Router,
    routing::{get, post},
};

#[tokio::main]
async fn main() {
    let app = Router::new()
        // ユーザー関連
        .route("/users", get(list_users))
        .route("/users/:id", get(get_user))
        .route("/users", post(create_user))
        // 投稿関連
        .route("/posts", get(list_posts))
        .route("/posts/:id", get(get_post))
        .route("/posts", post(create_post))
        // 認証関連
        .route("/login", post(login))
        .route("/logout", post(logout))
        .route("/register", post(register));

    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

こんな感じで書いていると、どんどんルートが増えていって大変ですよね…😅

ルーティングを分離しよう!

では、これを整理していきましょう。以下のような構成にします:

src/
├── main.rs
└── routes/
    ├── mod.rs     # ルートをまとめる
    ├── users.rs   # ユーザー関連
    ├── posts.rs   # 投稿関連
    └── auth.rs    # 認証関連

1. すっきりしたmain.rs

まず、main.rsをこんな感じで書きます:

mod routes;

#[tokio::main]
async fn main() {
    let app = routes::create_router();  // まだ作成していない

    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

ここで何をしているかというと、ルーティングの設定を関数として外部に切り出し、その関数を利用しています。

2. ルートをまとめるroutes/mod.rsを作成する

ルートをまとめるcreate_routerを書きます:

use axum::Router;

mod users;
mod posts;
mod auth;

pub fn create_router() -> Router {
    Router::new()
        .merge(users::create_router())  // まだ作成していない
        .merge(posts::create_router())  // まだ作成していない
        .merge(auth::create_router())  // まだ作成していない
}

3. routes/users.rsの作成

ユーザー関連のルートを分離します:

use axum::{
    Router,
    routing::{get, post},
};
use crate::handlers::users;

pub fn create_router() -> Router {
    Router::new()
        .route("/users", get(users::list_users))
        .route("/users/:id", get(users::get_user))
        .route("/users", post(users::create_user))
}

4. routes/posts.rsの作成

同様に投稿関連も分離:

use axum::{
    Router,
    routing::{get, post},
};
use crate::handlers::posts;

pub fn create_router() -> Router {
    Router::new()
        .route("/posts", get(posts::list_posts))
        .route("/posts/:id", get(posts::get_post))
        .route("/posts", post(posts::create_post))
}

5. routes/auth.rsの作成

認証関連も分離:

use axum::{
    Router,
    routing::post,
};

use crate::handlers::auth;

pub fn create_router() -> Router {
    Router::new()
        .route("/login", post(auth::login)
        .route("/logout", post(auth::logout))
        .route("/register", post(auth::register))
}

まとめ

一括で書いていたルーティングを機能ごとに分けることで、コードがとても管理しやすくなりました!

特に大規模なプロジェクトでは、この方法でルーティングを整理することをおすすめします。

次のステップとして、ハンドラーも同じように分離すると、さらにコードが整理されますよ!