cargo new rust-todo-api && cd rust-todo-api
cargo add axum tokio -F full
cargo add diesel -F postgres
cargo add serde -F derive
cargo add r2d2 # 連接池
?? AI 助攻
想自動生成帶注釋的Cargo.toml?用「代碼生成」提示詞,30 秒即可拿到模板,再交給「代碼優(yōu)化」移除冗余特性,編譯速度提升 20%!
cargo install diesel_cli --no-default-features -F postgres
diesel setup # 創(chuàng)建 migrations 目錄與 diesel.toml
diesel migration generate create_todos
migrations/2023-xx-xx_create_todos/up.sql
CREATE TABLE todos (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
completed BOOLEAN NOT NULL DEFAULT FALSE
);
down.sql
DROP TABLE todos;
diesel migration run # 生成 src/schema.rs
// src/main.rs
use axum::{
routing::{get, post, put, delete},
Router, Extension, Json, http::StatusCode,
};
use diesel::pg::PgConnection;
use diesel::r2d2::{self, ConnectionManager};
use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
type DbPool = r2d2::Pool<ConnectionManager<PgConnection>>;
#[tokio::main]
async fn main() {
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let manager = ConnectionManager::<PgConnection>::new(database_url);
let pool = r2d2::Pool::builder()
.build(manager)
.expect("Failed to create pool.");
let app = Router::new()
.route("/todos", get(get_todos).post(create_todo))
.route("/todos/:id", put(update_todo).delete(delete_todo))
.layer(Extension(pool));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
?? AI 審查
把「連接池配置」提交評審?「代碼審查助手」可自動檢查最大連接數(shù)、超時設置,提前發(fā)現(xiàn) 80% 性能隱患!
#[derive(Serialize, Deserialize)]
struct NewTodo {
title: String,
}
#[derive(Serialize, Deserialize)]
struct UpdateTodo {
title: Option<String>,
completed: Option<bool>,
}
async fn create_todo(
Extension(pool): Extension<DbPool>,
Json(new_todo): Json<NewTodo>,
) -> impl IntoResponse {
let conn = pool.get().expect("pool error");
let todo = diesel::insert_into(schema::todos::table)
.values(&new_todo.title)
.get_result::<Todo>(&conn)
.expect("insert error");
(StatusCode::CREATED, Json(todo))
}
async fn get_todos(Extension(pool): Extension<DbPool>) -> impl IntoResponse {
let conn = pool.get().expect("pool error");
let results = schema::todos::table.load::<Todo>(&conn).expect("select error");
Json(results)
}
async fn update_todo(
Extension(pool): Extension<DbPool>,
Path(id): Path<i32>,
Json(update): Json<UpdateTodo>,
) -> impl IntoResponse {
let conn = pool.get().expect("pool error");
diesel::update(schema::todos::table.find(id)))
.set(&update)
.execute(&conn)
.expect("update error");
StatusCode::OK
}
async fn delete_todo(
Extension(pool): Extension<DbPool>,
Path(id): Path<i32>,
) -> impl IntoResponse {
let conn = pool.get().expect("pool error");
diesel::delete(schema::todos::table.find(id)))
.execute(&conn)
.expect("delete error");
StatusCode::NO_CONTENT
}
export DATABASE_URL=postgres://user:pass@localhost/todo_db
cargo run
# 創(chuàng)建
curl -X POST localhost:3000/todos \
-H "Content-Type: application/json" \
-d '{"title":"Learn Rust"}'
# 列表
curl localhost:3000/todos
# 更新
curl -X PUT localhost:3000/todos/1 \
-H "Content-Type: application/json" \
-d '{"completed":true}'
# 刪除
curl -X DELETE localhost:3000/todos/1
? AI 補救
把「curl 測試命令」寫進 README 太麻煩?用「代碼文檔生成器」提示詞,自動在函數(shù)頭部生成標準注釋,提醒后續(xù)接入 Postman 集合,文檔一鍵達標!
thiserror 定義業(yè)務錯誤 + Axum 的 IntoResponseaxum-extra 的 TypedHeader 驗證 Bearerutoipa 自動生成 Swagger UIcargo test + cargo clippy通過本文的逐步指南,我們成功使用 Rust、Axum 和 Diesel 構建了一個功能齊全的 Todo API,涵蓋:
未來可在此基礎上添加身份驗證、更復雜的查詢邏輯以及其他功能,以滿足實際業(yè)務需求。希望本文能為您提供啟發(fā),祝編碼愉快!
?? 立即行動
把代碼 push 到 GitHub → 用 Fly.io / Render 一鍵部署 → 前端 React 調用,今晚就能擁有屬于自己的高性能 Todo API!
原文鏈接: https://docs.rapidapp.io/blog/building-a-todo-api-with-rust-axum-and-diesel