axum_mongodb/
lib.rs

1/*!
2# axum-mongodb
3
4[![GitHub Stars](https://img.shields.io/github/stars/yexiyue/axum-mongodb?style=flat-square)](https://github.com/yexiyue/axum-mongodb)
5[![Crates.io](https://img.shields.io/crates/v/axum-mongodb?style=flat-square)](https://crates.io/crates/axum-mongodb)
6
7**axum-mongodb** 是一个为 [Axum](https://github.com/tokio-rs/axum) Web 框架量身打造的库,旨在提供一种简洁且优雅的 MongoDB 集成方案。本库的设计灵感来源于著名的 JavaScript 框架 [Nest.js](https://nestjs.com/),致力于简化并提升 Axum 项目中对 MongoDB 数据库的操作效率。
8
9### 功能亮点
10
11- **基于状态管理的数据库连接**
12- **便捷的 CRUD 操作封装**
13
14### 安装
15
16在 `Cargo.toml` 中添加 axum-mongodb 依赖:
17
18```toml
19[dependencies]
20axum-mongodb = "0.2.1"
21```
22
23或通过 `cargo add` 命令快速安装:
24
25```bash
26cargo add axum-mongodb
27```
28
29### 使用教程
30
31#### 1. 初始化数据库连接
32
33在项目的入口点(如 `lib.rs`)中使用 `axum_mongodb::main` 属性宏来设置 MongoDB 连接和初始化数据库服务。
34
35```rust
36use anyhow::Result;
37use axum::{response::IntoResponse, routing::get, Router,Extension};
38use axum_mongodb::preload::*;
39use mongodb::{options::ClientOptions, Client};
40use tokio::net::TcpListener;
41
42// ...
43
44#[axum_mongodb::main]
45pub async fn start() -> Result<()> {
46    // 解析并创建 MongoDB 客户端配置
47    let client_options = ClientOptions::parse("mongodb://mongodb:password@localhost:21045/admin").await?;
48    let client = Client::with_options(client_options)?;
49    let db = client.database("todo");
50
51    // 创建 MongoDB 服务器状态实例
52    let mongodb_server = MongoDbServer::<Servers>::new(db).await;
53
54    // 构建 Axum 应用,并注入 MongoDB 状态到全局路由
55    let app = Router::new()
56        .route("/", get(hello_world))
57        .merge(todos_router())
58        // 注册State
59        .layer(Extension(mongodb_server));
60
61    // 启动服务器监听
62    let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
63    tracing::info!("Listening on http://{}", listener.local_addr().unwrap());
64    axum::serve(listener, app).await.unwrap();
65
66    Ok(())
67}
68
69async fn hello_world() -> impl IntoResponse {
70    "hello world"
71}
72```
73
74#### 2. 定义数据模型
75
76利用 `axum_mongodb::Column` Derive 宏装饰你的结构体以支持与 MongoDB 的交互:
77
78```rust
79use anyhow::Result;
80use axum_mongodb::futures::TryStreamExt;
81use bson::{self, doc, oid::ObjectId};
82use mongodb::{results::{DeleteResult, InsertOneResult, UpdateResult},};
83use serde::{Deserialize, Serialize};
84
85#[derive(Debug, Column, Deserialize, Serialize, Clone)]
86pub struct Todo {
87    #[serde(
88        serialize_with = "bson::serde_helpers::serialize_object_id_as_hex_string",
89        rename = "_id"
90    )]
91    id: ObjectId,
92    description: String,
93    completed: bool,
94    create_time: chrono::DateTime<chrono::Local>,
95    update_time: chrono::Local,
96}
97
98impl Server<Todo> {
99    pub async fn create_todo(&self, description: String) -> Result<InsertOneResult> {
100        Ok(self
101            .insert_one(
102                Todo {
103                    id: ObjectId::new(),
104                    description,
105                    completed: false,
106                    create_time: chrono::Local::now(),
107                    update_time: chrono::Local::now(),
108                },
109                None,
110            )
111            .await?)
112    }
113
114    // ... 其他CRUD方法实现
115}
116```
117
118#### 3. 在 Axum handler 中使用
119
120在处理函数中注入 `Server<Todo>` 实例,并调用相应的方法完成数据库操作:
121
122```rust
123use axum::{extract::Path, response::IntoResponse, Json};
124use serde::Deserialize;
125use super::Todo;
126use crate::Server;
127
128#[derive(Debug, Deserialize)]
129pub struct TodoQuery {
130    pub description: String,
131    pub completed: Option<bool>,
132}
133
134pub async fn create_todo(todo: Server<Todo>, Json(TodoQuery { description, .. }): Json<TodoQuery>) -> impl IntoResponse {
135    let res = todo.create_todo(description).await.unwrap();
136    Json(res)
137}
138```
139
140#### 4. 注册路由
141
142定义并组合相关路由,将 MongoDB 服务状态注入到路由模块中:
143
144```rust
145mod controller;
146use controller::{create_todo, delete_todo, get_todo, get_todos, update_todo};
147use axum::{
148    routing::{get, post},
149    Router,
150};
151
152pub use server::Todo;
153
154pub fn todos_router() -> Router{
155    Router::new()
156        .route("/todos", post(create_todo).get(get_todos))
157        .route("/todos/:id", get(get_todo).put(update_todo).delete(delete_todo))
158}
159
160```
161
162### 示例代码与文档
163
164完整的示例代码可参考 [axum-mongodb-example](https://github.com/yexiyue/axum-mongodb/blob/master/examples/axum/src/lib.rs)。同时,你可以查阅 [API 文档](https://apifox.com/apidoc/shared-6bef1065-5c3e-42a8-bf10-73e21f671fe1) 以获得更详细的信息和示例说明。
165
166### 更多信息
167
168请访问项目主页或查看仓库中的文档以获取更多关于如何在您的 Axum 项目中高效地集成和使用 MongoDB 的细节及高级功能。
169
170 */
171#[doc(hidden)]
172pub use axum::async_trait;
173
174pub use axum_mongodb_core::{inject, main, Column};
175
176#[doc(hidden)]
177pub use axum_mongodb_core::inject_meta;
178#[doc(hidden)]
179pub use futures;
180#[doc(hidden)]
181pub use mongodb;
182
183mod mongodb_server;
184pub use mongodb_server::MongoDbServer;
185
186pub mod preload {
187    //! 重新导出常用的结构体和宏
188
189    #[doc(hidden)]
190    pub use crate::CollectionInit;
191    pub use crate::MongoDbServer;
192    #[doc(hidden)]
193    pub use crate::NewWithDb;
194    pub use axum_mongodb_core::{inject, main, Column};
195    pub struct DBServers;
196}
197
198#[doc(hidden)]
199#[async_trait]
200pub trait NewWithDb {
201    async fn new(db: mongodb::Database) -> Self;
202}
203
204#[doc(hidden)]
205#[async_trait]
206pub trait CollectionInit {
207    async fn init(&self);
208}
209
210#[doc(hidden)]
211pub struct CreateIndexOptions {
212    pub keys: mongodb::bson::Document,
213    pub unique: bool,
214    pub name: Option<String>,
215}