見出し画像

「Rustでaxumを使いwebサーバーを作成する」のパート② フォルダー整理を行う

要件

axumを使いwebサーバーのフォルダーを整理せよ

タスク

axumを使いwebサーバーのフォルダーを整理せよ

参考記事

▼フォルダー分割やDIの設計で参考になります!

https://blog-dry.com/entry/2021/12/26/002649

学べること

  • RustPJでフォルダーを分割する方法

ヒント

現状のシンプルなフォルダー構成

tree

├── controller
│   ├── book_controller.rs
│   ├── health_controller.rs
│   ├── mod.rs
│   └── user_controller.rs
├── db
│   ├── mod.rs
│   ├── table.sql
│   └── table_dummy_data.sql
├── main.rs
└── router
    └── mod.rs

main.rs

use std::{net::SocketAddr, sync::Arc};
use axum::{
    Extension,
    Router,
};

mod controller;
mod db;
mod router;


#[tokio::main]
async fn main() -> std::io::Result<()> {
    let pool = db::conn().await;

    let app = Router::new()
        .nest("/health", router::health())
        .nest("/user", router::user())
        .nest("/book", router::book())
        .layer(Extension(Arc::new(pool)));

    let addr = SocketAddr::from(([127, 0, 0, 1], 3001));
    axum::Server::bind(&addr)
        .serve(app.into_make_service())
        .await
        .unwrap();
    Ok(())
}

db/mod.rs

use std::{env};
use sqlx::{MySql, MySqlPool, Pool};
use dotenv::dotenv;

// DBコネクションを取得
pub async fn conn() -> Pool<MySql> {
    dotenv().ok();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");

    let pool = MySqlPool::connect(&database_url)
        .await
        .unwrap();

    pool
}

router/mod.rs

use axum::{
    routing::{get},
    Router,
};
use crate::controller::book_controller::{get_list_book};
use crate::controller::health_controller::{health_check};
use crate::controller::user_controller::{get_by_id_user};


// healthのrouter
pub fn health() -> Router {
    Router::new()
        .route("/", get(health_check))
}

// userのrouter
pub fn user() -> Router {
    Router::new()
        .route("/", get(get_by_id_user))
}

// bookのrouter
pub fn book() -> Router {
    Router::new()
        .route("/", get(get_list_book))
}

controller/book_controller.rs

use axum::{
    response::Json,
    response::IntoResponse,
    http::StatusCode,
    Extension,
};
use std::{sync::Arc};
use chrono::NaiveDateTime;
use serde::Serialize;
use sqlx::{MySql, Pool};


#[derive(Serialize)]
struct Book {
    id: i64,
    title: String,
    author: String,
    publisher: String,
    isbn: String,
    comment: String,
    created_at: NaiveDateTime,
    updated_at: NaiveDateTime,
}

#[derive(Serialize)]
struct BookList(Vec<Book>);

type MySqlConPool = Arc<Pool<MySql>>;


pub async fn get_list_book(
    Extension(db): Extension<MySqlConPool>,
) -> Result<impl IntoResponse, StatusCode> {
    let conn = db.acquire().await;
    if conn.is_err() {
        return Err(StatusCode::INTERNAL_SERVER_ERROR);
    }

    sqlx::query_as!(Book, "select * from books")
        .fetch_all(&mut conn.unwrap())
        .await
        .map(|books| Json(BookList(books)))
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)
}

Cargo.toml

[package]
name = "tech-funding-backend"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
axum = "0.6.18"
chrono = { version = "0.4", features = ["serde"] }
dotenv = "0.15.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.96"
sqlx = { version = "0.6.3", features = ["runtime-tokio-rustls", "mysql", "chrono"] }
tokio = { version = "1.28.0", features = ["full"] }
uuid = "1.3.2"
tower-http = { version = "0.4.0", features = ["full"] }


ハマりポイント

  • 上記はDBのテーブル等がないとエラーになるので、まずはdocker等でDB を作成ないとエラーが出ます!まだな方は、まずは以下からです!


関連タグ

#rust #axum

この記事が気に入ったらサポートをしてみませんか?