
cURL 命令调用 Vertex AI Gemini API
编者按:本文于 2022 年 2 月 22 日更新,修复了与 Diesel 的连接问题,并进行了其他改进。
要继续本教程,你需要对 API 开发有基本了解,至少熟悉 CRUD(创建、读取、更新、删除)概念。本文将带你一步步学习如何使用 Rust 和 PostgreSQL 创建后端 API。
在开始编码之前,需要明确项目目标,并回顾完成演示所需的基本要求和假设。
我们将为一个示例员工管理应用程序创建完整的 CRUD API 端点。本项目是全新示例,旨在展示在 Rust 中编写 API 的基础构建块。
本指南适合对 Rust 有基本理解的读者,以下术语需熟悉:
首先,使用 Cargo 创建 Rust 项目:
cargo new employee
项目文件夹结构如下,可根据需要调整:
employee/
├─ src/
│ └─ employees/
│ ├─ mod.rs
│ ├─ model.rs
│ ├─ routes.rs
│ ├─ db.rs
│ └─ error_handlers.rs
│ └─ main.rs
├─ .env
└─ Cargo.toml
mod.rs
文件用于管理 employees
目录中模块:
mod model;
mod routes;
pub use model::*;
pub use routes::init_routes;
Cargo.toml
文件项目依赖项配置:
[package]
name = "employee"
version = "0.1.0"
authors = ["Ola John"]
edition = "2018"
[dependencies]
actix-web = "3.0"
actix-rt = "1.0"
chrono = { version = "0.4", features = ["serde"] }
dotenv = "0.11"
diesel = { version = "1.4", features = ["postgres", "r2d2", "uuid", "chrono"] }
diesel_migrations = "1.4"
env_logger = "0.6"
lazy_static = "1.4"
listenfd = "0.3"
serde = "1.0"
serde_json = "1.0"
r2d2 = "0.8"
uuid = { version = "0.6", features = ["serde", "v4"] }
主程序包含关键 crate 和配置:
actix-web
服务器设置示例:
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
dotenv().ok();
db::init();
let mut listenfd = ListenFd::from_env();
let mut server = HttpServer::new(|| App::new().configure(employees::init_routes));
server = match listenfd.take_tcp_listener(0)? {
Some(listener) => server.listen(listener)?,
None => {
let host = env::var("HOST").expect("Please set host in .env");
let port = env::var("PORT").expect("Please set port in .env");
server.bind(format!("{}:{}", host, port))?
}
};
server.run().await
}
API 端点定义在 routes.rs
中。使用 serde 进行 JSON 序列化和反序列化。
#[get("/employees")]
async fn find_all() -> Result<HttpResponse, Error> {
let employees = web::block(|| Employees::find_all()).await.unwrap();
Ok(HttpResponse::Ok().json(employees))
}
#[get("/employees/{id}")]
async fn find(id: web::Path<i32>) -> Result<HttpResponse, Error> {
let employee = Employees::find(id.into_inner())?;
Ok(HttpResponse::Ok().json(employee))
}
#[post("/employees")]
async fn create(employee: web::Json<Employee>) -> Result<HttpResponse, Error> {
let employee = Employees::create(employee.into_inner())?;
Ok(HttpResponse::Ok().json(employee))
}
#[put("/employees/{id}")]
async fn update(
id: web::Path<i32>,
employee: web::Json<Employee>,
) -> Result<HttpResponse, Error> {
let employee = Employees::update(id.into_inner(), employee.into_inner())?;
Ok(HttpResponse::Ok().json(employee))
}
#[delete("/employees/{id}")]
async fn delete(id: web::Path<i32>) -> Result<HttpResponse, Error> {
let deleted_employee = Employees::delete(id.into_inner())?;
Ok(HttpResponse::Ok().json(json!({ "deleted": deleted_employee })))
}
pub fn init_routes(config: &mut web::ServiceConfig) {
config.service(find_all);
config.service(find);
config.service(create);
config.service(update);
config.service(delete);
}
db.rs
文件示例:
use crate::error_handler::CustomError;
use diesel::pg::PgConnection;
use diesel::r2d2::ConnectionManager;
use lazy_static::lazy_static;
use r2d2;
use std::env;
type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;
pub type DbConnection = r2d2::PooledConnection<ConnectionManager<PgConnection>>;
embed_migrations!();
lazy_static! {
static ref POOL: Pool = {
let db_url = env::var("DATABASE_URL").expect("Database url not set");
let manager = ConnectionManager::<PgConnection>::new(db_url);
Pool::new(manager).expect("Failed to create db pool")
};
}
pub fn init() {
lazy_static::initialize(&POOL);
let conn = connection().expect("Failed to get db connection");
embedded_migrations::run(&conn).unwrap();
}
pub fn connection() -> Result<DbConnection, CustomError> {
POOL.get()
.map_err(|e| CustomError::new(500, format!("Failed getting db connection: {}", e)))
}
Diesel 简化数据库查询和对象映射。
#[derive(Serialize, Deserialize, AsChangeset, Insertable)]
#[table_name = "employees"]
pub struct Employee {
pub first_name: String,
pub last_name: String,
pub department: String,
pub salary: i32,
pub age: i32,
}
#[derive(Serialize, Deserialize, Queryable)]
pub struct Employees {
pub id: i32,
pub first_name: String,
pub last_name: String,
pub department: String,
pub salary: i32,
pub age: i32,
}
启动项目:
cargo watch -x run
通过 API 端点,可以在数据库中执行 CRUD 操作:创建、读取、更新和删除员工记录。
通过本教程,你已经掌握了如何使用 Actix 在 Rust 中创建 API 端点,并处理 CRUD 操作,同时使用 Diesel 管理 Postgres 数据。
Rust 编译器确保高可靠性,成功编译几乎保证代码功能正确。这使开发过程更加高效、可维护。
原文链接: https://blog.logrocket.com/create-backend-api-with-rust-postgres/