玩了一段时间 Vapor,想不明白谁家会用 swift 跑生产,可能也就 perfect
维护者背后的公司会用,至少在拆哪应该还是要快(la)准(man)狠(kpi)的。
rust 社区中关注了 rocket
一段时间,后面发现 actix-web
在各方面更有优势,加上要好好点 rust 技能树,所以就选定这个了。
这里会以重构我的闹钟后端作为蓝本,逐步做个记录。
TL;DR
- 直接用
cargo
创建应用 - 装载
actix-web
- 写一个 api
创建应用
官方没有开箱即用的模板,所以还是从cargo new
开始,这里定义了默认使用git
作为版本控制
> cargo new --vcs git actix-demo
在Cargo.toml
中添加这些
[dependencies]
actix-web = "2.0"
actix-rt = "1.0"
# env
dotenv = "0.15.0"
log = "0.4.8"
env_logger = "0.7.1"
然后在main.rs
创建启动函数
use actix_web::{App, HttpServer, get};
#[get("/")]
fn index() -> HttpResponse {
HttpResponse::Ok().body("Hello World")
}
#[actix_rt::main]
async fn main() -> io::Result<()> {
let app = || App::new().service(index);
info!("serving on localhost:7001");
HttpServer::new(app)
.bind("localhost:7001")?
.run()
.await
}
一般来说这样就可以运行了
配置应用
按照习惯,工程结构还是愿意设置成这样:
- controller
- services
- models
- middleware
所以目录先确定下来:
+-- src
| +-- controller
| | +-- mod.rs
| +-- services
| | +-- mod.rs
| +-- models
| | +-- mod.rs
| +-- middleware
| | +-- mod.rs
为什么每个目录下都需要mod.rs
?原因是人家rust
对模块就是这么处理的啊!
接着,Cargo.toml
需要加点东西,比如json
的支持(可是你用的不是 GraphQL 吗!)
[dependencies]
# serde
serde = "1.0.104"
serde_derive = "1.0.104"
serde_json = "1.0.44"
json = "0.12.0"
接下来对代码作出一些改动,首先是一个通用的json
结构体,创建 models/payload
use serde_derive::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Clone)]
pub struct Payload<T> {
pub code: isize,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub payload: Option<T>,
}
接着,从controller/index
开始
#[derive(Deserialize)]
struct Info {
message: String
}
#[get("/")]
pub async fn index(query: web::Query<Info>) -> Result<HttpResponse, Error> {
// 在Query拿到与 Info 结构一样的参数
// 如果你这么写,那么如果调用时如果不传 query 会报错,param 同理
// rust 真严格..
let result = crate::services::index::get_helloworld(query.message.clone());
Ok(HttpResponse::Ok().json(result))
}
然后,services/index
,暂时不用middleware
use crate::models::payload::Payload;
// 简单写一个服务
pub fn get_helloworld(msg: String) -> Payload<()> {
Payload {
code: 0,
message: msg.to_string(),
payload: None
}
}
最后改一下main.rs
+mod controllers;
+mod models;
+mod services;
#[actix_rt::main]
async fn main() -> io::Result<()> {
let app = || App::new()
- .service(index);
+ .service(controllers::index::index);
info!("serving on localhost:7001");
HttpServer::new(app)
.bind("localhost:7001")?
.run()
.await
测试一下,调用 localhost:7001?message=helloworld
,就可以看到回复了!
{
"code": 0,
"message": "helloworld"
}
代码里我其实还用这些:
router
- 写了一个配置的结构体用来封装 HOST, PORT 和数据库地址
- 环境变量配置
文章就不写了,大概就那样。
后记
- 建议用 CLion,VSCode 和 VIM 实在是太… IDE 也好,数据库分步调试什么的很方便
- 没 key 怎么办,找一个长期维护的开源项目,嫖就完事儿了
- 前端本来也想用
rust(yew)
的,可是在raspbian
运行,不清楚结果。也不清楚其他选型,所以只能继续electron + react
了,可能会去掉umi
下一期整数据库连接