|
| 1 | +# Cursor AI通用规则 |
| 2 | +- 本项目使用Rust语言编写,使用Rust的标准库和第三方库来实现。 |
| 3 | +- 本项目的代码必须符合Rust的编码规范,使用Rust的最佳实践。 |
| 4 | +- 本项目的代码必须符合Rust的安全规范,使用Rust的安全特性。在编写代码时,必须注意避免潜在的安全问题。定义函数的时候,参数定义借用优先于clone。 |
| 5 | +- 本项目的代码必须符合Rust的性能规范,使用Rust的性能特性。在编写代码时,必须注意避免潜在的性能问题。 |
| 6 | + |
| 7 | +# models定义规范 |
| 8 | +- models定义在src/models目录下,下面是models定义的范例: |
| 9 | +数据库表定义的模型: |
| 10 | +```txt |
| 11 | +UserLogin: #模型的名字 |
| 12 | + # 用户信息 |
| 13 | + @pg varchar(32) #输出到SQL的类型定义 |
| 14 | + @rust String #输出到Rust代码的类型定义 |
| 15 | + username: 用户名 #字段的名称和注释 |
| 16 | + |
| 17 | + @pg varchar(256) |
| 18 | + @rust String |
| 19 | + password: 密码 |
| 20 | + |
| 21 | + @pg INT |
| 22 | + @rust i32 |
| 23 | + ts: 时间戳 |
| 24 | +``` |
| 25 | +数据库表定义的模型输出到 src/models/models.txt |
| 26 | + |
| 27 | +handler函数参数模型的定义: |
| 28 | +```txt |
| 29 | +LoginForm: #模型的名字 |
| 30 | + # 登陆表单 |
| 31 | + @rust String #输出到Rust代码的类型定义 |
| 32 | + @ts string #输出到TypeScript代码的类型定义 |
| 33 | + username: 用户名 #字段的名称和注释 |
| 34 | + |
| 35 | + @rust String |
| 36 | + @ts string |
| 37 | + password: 密码 |
| 38 | +``` |
| 39 | +handler函数参数模型的定义输出到 src/models/forms.txt |
| 40 | + |
| 41 | +handler函数返回模型的定义: |
| 42 | +```txt |
| 43 | +StatusResponse: #模型的名字 |
| 44 | + # 状态码 |
| 45 | + @rust String #输出到Rust代码的类型定义 |
| 46 | + @ts string #输出到TypeScript代码的类型定义 |
| 47 | + status: 状态值 #字段的名称和注释 |
| 48 | +``` |
| 49 | +handler函数返回模型的定义输出到 src/models/responses.txt |
| 50 | + |
| 51 | +定义完模型后需要运行 ./scripts/sync.sh 来同步生成代码. |
| 52 | +生成代码后需要在src/main.rs中加入新生成模型的引用 |
| 53 | +修改的部分如下: |
| 54 | +```rust |
| 55 | +#[derive(OpenApi)] |
| 56 | +#[openapi( |
| 57 | +paths( |
| 58 | + openapi, |
| 59 | + example::handlers::it_works, |
| 60 | +), |
| 61 | +components( |
| 62 | + schemas( |
| 63 | + ErrResponse |
| 64 | + // 新生成的模型需要加入到这里 |
| 65 | + ), |
| 66 | +), |
| 67 | +)] |
| 68 | +struct ApiDoc; |
| 69 | +``` |
| 70 | + |
| 71 | +# handler函数定义规范 |
| 72 | +- handler函数定义在src/mod_name 目录下,handlers.rs 中 下面是handler函数定义的范例: |
| 73 | +```rust |
| 74 | +#[utoipa::path( |
| 75 | + 请求的method get 或者 post, |
| 76 | + path = "handler的访问路径,参数用:参数名 的形式定义", |
| 77 | + request_body = Json Body的类型名字, // 如果有才要定义,没有就不填这一项 |
| 78 | + params(路径参数的类型, 查询参数的类型) // 如果有才要定义,没有就不填这一项 |
| 79 | + responses( |
| 80 | + (status = 200, description = "handler函数的功能说明", body = 返回的类型), |
| 81 | + (status = 500, description = "服务器错误", body = ErrResponse), |
| 82 | + (status = 401, description = "认证失败", body = ErrResponse), |
| 83 | + (status = 403, description = "没有权限", body = ErrResponse) |
| 84 | + ), |
| 85 | + security( |
| 86 | + ("bearerAuth" = []) |
| 87 | + ) |
| 88 | +)] |
| 89 | +pub async fn 函数名( |
| 90 | + State(state): State<AppContext>, // 如果有状态需要传入,没有就不填这一项 |
| 91 | + Path(路径参数): Path<路径参数的类型>, // 如果有路径参数,没有就不填这一项 |
| 92 | + Query(查询参数): Query<查询参数的类型>, // 如果有查询参数,没有就不填这一项 |
| 93 | + Json(请求体): Json<请求体的类型>, // 如果有请求体,没有就不填这一项) |
| 94 | +) -> APIResult<返回的类型> { |
| 95 | +} |
| 96 | +``` |
| 97 | +在创建了handler函数后需要在 handlers.rs 中的router函数中加入路由定义 |
| 98 | +```rust |
| 99 | +pub fn router(state: AppContext) -> Router { |
| 100 | + Router::new() |
| 101 | + .route("/", get(函数名)) |
| 102 | + // 加入到这里,比如 .route("handler的访问路径,参数用:参数名 的形式定义", 请求的method(函数名)) |
| 103 | + .with_state(state) |
| 104 | +} |
| 105 | +``` |
| 106 | +另外还要在app.rs 最后面的 |
| 107 | +```rust |
| 108 | +#[derive(OpenApi)] |
| 109 | +#[openapi( |
| 110 | +paths( |
| 111 | + openapi, |
| 112 | + example::handlers::it_works, |
| 113 | + // 加入到这里,比如.模型名::handlers::handler函数名 |
| 114 | +), |
| 115 | +components( |
| 116 | + schemas( |
| 117 | + ErrResponse |
| 118 | + ), |
| 119 | +), |
| 120 | +)] |
| 121 | +``` |
| 122 | +# service结构体定义规范 |
| 123 | +- service结构体定义在src/services 目录下,每个service定义一个文件:服务名_services.rs,下面是service结构体定义的范例: |
| 124 | +```rust |
| 125 | +pub struct 服务名Services { |
| 126 | + pub(crate) db: sqlx::Pool<sqlx::Postgres>, |
| 127 | + pub(crate) redis: RedisHolder, |
| 128 | +} |
| 129 | +impl Service for 服务名Services { |
| 130 | + fn init(db: sqlx::Pool<sqlx::Postgres>, redis: RedisHolder) -> Self { |
| 131 | + Self{db, redis} |
| 132 | + } |
| 133 | +} |
| 134 | +``` |
| 135 | +在创建了service结构体后需要在 mod.rs 中的init函数中将Service注入到DI容器中 |
| 136 | +```rust |
| 137 | +// 先添加 |
| 138 | +pub mod 服务名_service; |
| 139 | + |
| 140 | +// 再注册 |
| 141 | +pub async fn init() { |
| 142 | + register_service::<ExampleServices>(); |
| 143 | + // 加入到这里,比如 register_service::<服务名Services>(); |
| 144 | +} |
| 145 | + |
| 146 | +``` |
0 commit comments