本文需要用到以下工具/库:
- Rust and Cargo toolchain
actix-web
web 框架sea-orm
ORM 框架serde
序列化/反序列化dotenvy
环境变量配置
项目初始化
首先 cargo new workspace
创建一个新项目,但该项目只作为workspace
工作空间,因此可以将src
目录直接删掉,然后编辑Cargo.toml
:
1 | [workspace] |
设置default-members
,这样cargo run
的默认项目就是app
。
然后,cargo new app
,新建app
crate。接着给app
的Cargo.toml
添加如下依赖:
1 | [dependencies] |
actix 准备
首先我们到app
的 main.rs
,把 actix
先跑起来看看。
1 | use actix_web::{web, App, HttpServer}; |
cargo run
然后 curl http://localhost:5000
,你会看到一个”pong!”.
用 dotenvy 控制环境变量
监听选项写死是不太好的,这时可以使用dotenvy
包。在workspace目录下创建一个.env
文件,内容为:
1 | LISTEN=0.0.0.0 |
然后,我们在main中通过读取环境变量来实现动态配置。
1 | // main.rs |
数据库准备
本例使用 Sea-Orm 作为 ORM 框架。 首先安装 sea-orm-cli 准备数据库迁移。
1 | cargo install sea-orm-cli |
Schema first 还是 Entity first?
SeaORM文档也提到了这个问题。
对于涉及数据库的业务,有一个重要的开发流程问题,那就是先有数据库还是先有代码?.NET EntityFrame Core 的文档给了很好的说明。大多数业务框架推荐 Entity First(Code First)。即先有业务模型,然后去生成数据库。这是因为数据库通常是通过 SQL 管理的,而在有ORM框架的情况下,应当尽可能减少原生SQL操作。
但是SeaORM采用了一个折中的工作流程,Schema First
。首先,应当写一个迁移逻辑(用Rust
而非SQL
),然后根据这个迁移逻辑去调整数据库,最后从迁移过的数据库生成Entity
,也就代码中的Model
。这一套流程和EF Core
的Code First
模式是很像的,只不过EF Core
会先从Model
的变化生成迁移文件(这些推断并不总是准确的,而且可能造成毁灭性的后果)。另一些ORM框架,比如gorm
,它们的自动迁移只会新增而不会修改或删除,为了避免不可挽回的数据丢失,但是这种情况下,修改一个现有字段的约束就会变得困难。事实上,SeaORM的工作模式虽然相比之下更麻烦了一点,但是开发者获得了更多的控制权,而且由于迁移文件也是用Rust
代码写的,效率并不会很低。
执行sea-orm-cli migrate init
,我们会得到一个新的Crate,名叫migration
。然后删掉默认的一个示例迁移文件。
添加 migration Crate 到 WorkSpace
接下来,修改workspace
即根目录的Cargo.toml
以包含这个 migration
Crate.
1 | [workspace] |
Migration File
通过sea-orm-cli migrate generate create_todo_table
,可以得到一个以当前时间为前缀,名为create_todo_table
的迁移文件。修改其内容如下:
1 | use sea_orm_migration::prelude::*; |
这样,就定义好了一次迁移的逻辑。up
方法新建了一张表,并设置了字段的类型和约束。down
方法应当是up
的逆过程,由于up
是新建表,因此down
直接删除表就可以了。
执行迁移
接下来,我们要将写好的迁移文件应用到数据库。可以在应用程序中完成这一步,也可以使用sea-orm-cli
完成。migration
Crate是一个 bin crate,它编译的结果就是一个负责执行迁移的程序。sea-orm-cli
提供了一个捷径来编译并执行迁移。
如果采用sea-orm-cli
手动迁移,要注意为migration
crate配置一个数据库驱动,就像app
crate一样,本文以sqlite为例。
需要用到环境变量DATABASE_URL
,由于我们已经使用了dotenvy
来管理环境变量,而sea-orm-cli
也是支持这个的,因此直接在.env
文件添加一行:
1 | # .env |
1 | # ./migration/Cargo.toml |
然后,执行sea-orm-cli migrate
,等待编译并运行成功后,数据库就迁移完成了!
生成 Entity
要执行 CRUD,当然还需要 Entity 定义,可以用sea-orm-cli
从线上数据库生成。注意是从数据库生成,而不是从前面编写的 migration 文件。因此务必确保所连接到的数据库Schema是最新的!
执行sea-orm-cli generate entity
,会发现生成了三个文件,默认是一个mod
的构造,即mod.rs
,prelude.rs
以及若干个 Entity
定义,由于我们只有一个todo
,因此也只有一个todo.rs
。
不过默认生成在了当前目录下,显然不太合理。你可以根据自己的需要调整目录结果,通过-o
参数来指定生成位置。
CRUD API
然后,我们就可以开始进入无聊的CRUD环节了。无聊的代码就不贴了,详见github.com/artiga033/rust_rest_api_demo
Permalink: http://blog.artiga.top/2022/write-web-api-with-rust/
本文采用CC BY-NC-SA 4.0许可
Comments