5 releases

1.0.3 Jan 7, 2024
0.2.2 Jan 12, 2024
0.1.1 Jan 6, 2024

#1734 in Database interfaces

MIT license

17KB
142 lines

axum-mongodb

GitHub Stars Crates.io

axum-mongodb 是一个为 Axum Web 框架量身打造的库,旨在提供一种简洁且优雅的 MongoDB 集成方案。本库的设计灵感来源于著名的 JavaScript 框架 Nest.js,致力于简化并提升 Axum 项目中对 MongoDB 数据库的操作效率。

功能亮点

  • 基于状态管理的数据库连接
  • 便捷的 CRUD 操作封装

安装

Cargo.toml 中添加 axum-mongodb 依赖:

[dependencies]
axum-mongodb = "0.2.1"

或通过 cargo add 命令快速安装:

cargo add axum-mongodb

使用教程

1. 初始化数据库连接

在项目的入口点(如 lib.rs)中使用 axum_mongodb::main 属性宏来设置 MongoDB 连接和初始化数据库服务。

use anyhow::Result;
use axum::{response::IntoResponse, routing::get, Router,Extension};
use axum_mongodb::preload::*;
use mongodb::{options::ClientOptions, Client};
use tokio::net::TcpListener;

// ...

#[axum_mongodb::main]
pub async fn start() -> Result<()> {
    // 解析并创建 MongoDB 客户端配置
    let client_options = ClientOptions::parse("mongodb://mongodb:password@localhost:21045/admin").await?;
    let client = Client::with_options(client_options)?;
    let db = client.database("todo");

    // 创建 MongoDB 服务器状态实例
    let mongodb_server = MongoDbServer::<Servers>::new(db).await;

    // 构建 Axum 应用,并注入 MongoDB 状态到全局路由
    let app = Router::new()
        .route("/", get(hello_world))
        .merge(todos_router())
        // 注册State
        .layer(Extension(mongodb_server));

    // 启动服务器监听
    let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
    tracing::info!("Listening on http://{}", listener.local_addr().unwrap());
    axum::serve(listener, app).await.unwrap();

    Ok(())
}

async fn hello_world() -> impl IntoResponse {
    "hello world"
}

2. 定义数据模型

利用 axum_mongodb::Column Derive 宏装饰你的结构体以支持与 MongoDB 的交互:

use anyhow::Result;
use axum_mongodb::futures::TryStreamExt;
use bson::{self, doc, oid::ObjectId};
use mongodb::{results::{DeleteResult, InsertOneResult, UpdateResult},};
use serde::{Deserialize, Serialize};

#[derive(Debug, Column, Deserialize, Serialize, Clone)]
pub struct Todo {
    #[serde(
        serialize_with = "bson::serde_helpers::serialize_object_id_as_hex_string",
        rename = "_id"
    )]
    id: ObjectId,
    description: String,
    completed: bool,
    create_time: chrono::DateTime<chrono::Local>,
    update_time: chrono::Local,
}

impl Server<Todo> {
    pub async fn create_todo(&self, description: String) -> Result<InsertOneResult> {
        Ok(self
            .insert_one(
                Todo {
                    id: ObjectId::new(),
                    description,
                    completed: false,
                    create_time: chrono::Local::now(),
                    update_time: chrono::Local::now(),
                },
                None,
            )
            .await?)
    }

    // ... 其他CRUD方法实现
}

3. 在 Axum handler 中使用

在处理函数中注入 Server<Todo> 实例,并调用相应的方法完成数据库操作:

use axum::{extract::Path, response::IntoResponse, Json};
use serde::Deserialize;
use super::Todo;
use crate::Server;

#[derive(Debug, Deserialize)]
pub struct TodoQuery {
    pub description: String,
    pub completed: Option<bool>,
}

pub async fn create_todo(todo: Server<Todo>, Json(TodoQuery { description, .. }): Json<TodoQuery>) -> impl IntoResponse {
    let res = todo.create_todo(description).await.unwrap();
    Json(res)
}

4. 注册路由

定义并组合相关路由,将 MongoDB 服务状态注入到路由模块中:

mod controller;
use controller::{create_todo, delete_todo, get_todo, get_todos, update_todo};
use axum::{
    routing::{get, post},
    Router,
};

pub use server::Todo;

pub fn todos_router() -> Router{
    Router::new()
        .route("/todos", post(create_todo).get(get_todos))
        .route("/todos/:id", get(get_todo).put(update_todo).delete(delete_todo))
}

示例代码与文档

完整的示例代码可参考 axum-mongodb-example。同时,你可以查阅 API 文档 以获得更详细的信息和示例说明。

更多信息

请访问项目主页或查看仓库中的文档以获取更多关于如何在您的 Axum 项目中高效地集成和使用 MongoDB 的细节及高级功能。

Dependencies

~28–40MB
~730K SLoC