「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 を作成ないとエラーが出ます!まだな方は、まずは以下からです!
関連タグ
この記事が気に入ったらサポートをしてみませんか?