1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
/*!
## axum-mongodb
本库旨在为Axum项目提供一种更为简洁且优雅的MongoDB集成方案,其设计灵感来源于知名框架[Nest.js](https://nestjs.com/)。通过使用本库,开发者能够在Axum项目中实现对MongoDB数据库的高度简化及高效利用。
### 使用方式
#### 1.安装依赖
```bash
cargo add axum-mongodb
```
#### 2.在入口函数使用main属性宏
**lib.rs**
```rust
use anyhow::Result;
use axum::{response::IntoResponse, routing::get, Router};
use axum_mongodb::preload::*;
use mongodb::{options::ClientOptions, Client};
use tokio::net::TcpListener;
pub mod error;
mod todos;
use todos::Todo;
use crate::todos::todos_router;
// 在lib中使用,这样生成的结构体才能在整个项目中使用
#[axum_mongodb::main]
pub async fn start() -> Result<()> {
let client_options =
ClientOptions::parse("mongodb://mongodb:password@localhost:21045/admin").await?;
let client = Client::with_options(client_options)?;
let db = client.database("todo");
// 定义State(关键代码)
let mongodb_server = MongoDbServer::<Servers>::new(db).await;
let app = Router::new()
.route("/", get(hello_world))
.merge(todos_router())
// 注册State
.with_state(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"
}
```
**main.rs**
```rust
use anyhow::Result;
#[tokio::main]
async fn main() -> Result<()> {
axum_example::start().await?;
Ok(())
}
```
#### 3.在结构体上使用Column Derive宏
```rust
use crate::Server;
use anyhow::Result;
use axum_mongodb::futures::TryStreamExt;
// 导入axum-mongodb
use axum_mongodb::preload::*;
use mongodb::{
bson::{self, doc, oid::ObjectId},
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::DateTime<chrono::Local>,
}
// 实现相应方法,在handler中可以调用到
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?)
}
// ...
}
```
#### 4.在axum handler中使用
```rust
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)
}
// ...
```
#### 5.注册路由
```rust
mod controller;
use controller::{create_todo, delete_todo, get_todo, get_todos, update_todo};
mod server;
use axum::{
routing::{get, post},
Router,
};
use axum_mongodb::MongoDbServer;
pub use server::Todo;
use crate::Servers;
pub fn todos_router() -> Router<MongoDbServer<Servers>> {
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](https://github.com/yexiyue/axum-mongodb/blob/master/examples/axum/src/lib.rs),[示例api文档](https://apifox.com/apidoc/shared-6bef1065-5c3e-42a8-bf10-73e21f671fe1)
*/
#[doc(hidden)]
pub use axum::async_trait;
pub use axum_mongodb_core::{inject, main, Column};
#[doc(hidden)]
pub use axum_mongodb_core::inject_meta;
#[doc(hidden)]
pub use futures;
#[doc(hidden)]
pub use mongodb;
mod mongodb_server;
pub use mongodb_server::MongoDbServer;
pub mod preload {
//! 重新导出常用的结构体和宏
#[doc(hidden)]
pub use crate::CollectionInit;
pub use crate::MongoDbServer;
#[doc(hidden)]
pub use crate::NewWithDb;
pub use axum_mongodb_core::{inject, main, Column};
pub struct DBServers;
}
#[doc(hidden)]
#[async_trait]
pub trait NewWithDb {
async fn new(db: mongodb::Database) -> Self;
}
#[doc(hidden)]
#[async_trait]
pub trait CollectionInit {
async fn init(&self);
}
#[doc(hidden)]
pub struct CreateIndexOptions {
pub keys: mongodb::bson::Document,
pub unique: bool,
pub name: Option<String>,
}