
eDRV的EV充电应用API:革新电动汽车即插即充体验
在本教程中,我们将使用 Rust、MongoDB 和 Actix Web 创建一个支持 创建、读取、更新和删除(CRUD) 操作的 REST API。以 Person
和 Hobby
两个模型为例,这两个模型存在一对多关系:在 MongoDB 中,Hobby
集合通过引用 Person
的 ID 来实现关联。
最终,我们将实现如下 REST API 端点:
POST /api/v1/persons
:创建新 PersonGET /api/v1/persons
:获取所有 PersonGET /api/v1/persons/:id
:根据 ID 获取指定 PersonPUT /api/v1/persons/:id
:更新指定 PersonDELETE /api/v1/persons/:id
:删除指定 PersonPOST /api/v1/hobbies
:创建新 HobbyGET /api/v1/hobbies
:获取所有 HobbyGET /api/v1/hobbies/:id
:根据 ID 获取指定 HobbyPUT /api/v1/hobbies/:id
:更新指定 HobbyDELETE /api/v1/hobbies/:id
:删除指定 Hobby在开始之前,请确保已安装:
brew tap mongodb/brew
brew install mongodb-community
brew services start mongodb/brew/mongodb-community
brew services list
use admin
db.createUser({
user: "rustadmin",
pwd: "Adm1n_pwd",
roles: ["readWrite", "dbAdmin"]
})
编辑 MongoDB 配置文件:
security:
authorization: "enabled"
保存后重启服务:
brew services restart mongodb/brew/mongodb-community
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustc -V
cargo -V
安装扩展:
cargo new rust_mongo_rest
cd rust_mongo_rest
项目结构:
rust_mongo_rest/
├── Cargo.toml
└── src/
└── main.rs
在 Cargo.toml
中添加:
[dependencies]
actix-web = "4"
mongodb = "3.1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
dotenv = "0.15"
futures = "0.3"
tokio = { version = "1", features = ["full"] }
chrono = { version = "*", features = ["serde"] }
运行:
cargo build
.env
DB_USERNAME=rustadmin
DB_PASSWORD=Adm1n_pwd
DB_URL=mongodb://localhost:27017
DB_NAME=rust_mongo
DB_AUTH_SOURCE=admin
src/db.rs
)use mongodb::{options::{ClientOptions, Credential}, Client};
use std::env;
pub async fn get_mongo_client() -> Client {
dotenv::dotenv().ok();
let username = env::var("DB_USERNAME").expect("DB_USERNAME must be set");
let password = env::var("DB_PASSWORD").expect("DB_PASSWORD must be set");
let host = env::var("DB_URL").unwrap_or_else(|_| "localhost".to_string());
let auth_source = env::var("DB_AUTH_SOURCE").unwrap_or_else(|_| "admin".to_string());
let credential = Credential::builder()
.username(Some(username))
.password(Some(password))
.source(Some(auth_source))
.build();
let client_options = ClientOptions::builder()
.hosts(vec![host])
.credential(Some(credential))
.build();
Client::with_options(client_options).unwrap()
}
mkdir src/models
touch src/models/person.rs
touch src/models/hobby.rs
touch src/models/mod.rs
person.rs
:
use mongodb::bson::oid::ObjectId;
use serde::{Deserialize, Serialize};
use chrono::Utc;
#[derive(Debug, Serialize, Deserialize)]
pub struct Person {
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
pub id: Option<ObjectId>,
pub name: String,
pub email: String,
pub created_at: chrono::DateTime<Utc>,
}
hobby.rs
:
use mongodb::bson::oid::ObjectId;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct Hobby {
#[serde(rename = "_id", skip_serializing_if = "Option::is_none")]
pub id: Option<ObjectId>,
pub hobby_name: String,
pub description: String,
pub person: Option<ObjectId>,
}
mod.rs
:
pub mod person;
pub mod hobby;
mkdir src/handlers
touch src/handlers/person.rs
touch src/handlers/hobby.rs
touch src/handlers/mod.rs
在 person.rs
和 hobby.rs
中实现 CRUD 逻辑。
src/routes.rs
)use actix_web::web;
use crate::handlers::{person, hobby};
pub fn configure_routes(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("/api/v1")
.route("/persons", web::post().to(person::create_person))
.route("/persons", web::get().to(person::get_persons))
.route("/persons/{id}", web::get().to(person::get_person_by_id))
.route("/persons/{id}", web::put().to(person::update_person_by_id))
.route("/persons/{id}", web::delete().to(person::delete_person_by_id))
.route("/hobbies", web::post().to(hobby::create_hobby))
.route("/hobbies", web::get().to(hobby::get_hobbies))
.route("/hobbies/{id}", web::get().to(hobby::get_hobby_by_id))
.route("/hobbies/{id}", web::put().to(hobby::update_hobby_by_id))
.route("/hobbies/{id}", web::delete().to(hobby::delete_hobby_by_id)),
);
}
main.rs
)use actix_web::{App, HttpServer};
use crate::db::get_mongo_client;
mod db;
mod models;
mod handlers;
mod routes;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let client = get_mongo_client().await;
HttpServer::new(move || {
App::new()
.app_data(client.clone())
.configure(routes::configure_routes)
})
.bind("127.0.0.1:8080")?
.run()
.await
}
启动应用:
cargo run
示例:创建 Person
curl -X POST http://127.0.0.1:8080/api/v1/persons \
-H "Content-Type: application/json" \
-d '{"name": "Graydon Hoare", "email": "graydon@example.com"}'
通过本教程,你已成功使用 Rust、MongoDB 和 Actix Web 构建了一个完整的 CRUD REST API,支持一对多模型关联,可作为后续业务扩展的基础。