-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrust-actix.mdc
More file actions
127 lines (105 loc) · 8.28 KB
/
Copy pathrust-actix.mdc
File metadata and controls
127 lines (105 loc) · 8.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
---
description: Idiomatic Rust rules — no unwrap in prod, typed errors, async-safe patterns.
globs: ""
alwaysApply: true
---
## File Structure and Module Organization
- All source code lives in `src/` directory. No exceptions.
- HTTP handlers go in `src/handlers/` with one file per resource: `src/handlers/users.rs`, `src/handlers/posts.rs`.
- Domain logic goes in `src/domain/` with subdirectories by entity: `src/domain/users/`, `src/domain/posts/`.
- Database queries go in `src/db/` with one file per table: `src/db/users.rs`, `src/db/posts.rs`.
- Error types go in `src/errors.rs` — single file, not scattered.
- Configuration goes in `src/config.rs` — single file, loaded at startup only.
- Tests live in `src/tests/` with structure mirroring `src/`: `src/tests/handlers/users.rs`.
- Integration tests live in `tests/` directory at project root, not in `src/`.
- Middleware goes in `src/middleware/` with one file per middleware: `src/middleware/auth.rs`, `src/middleware/logging.rs`.
- Never create `utils.rs` or `helpers.rs` — name files by what they do: `src/crypto.rs`, `src/validation.rs`.
## Naming Conventions
- File names are snake_case: `user_service.rs`, not `UserService.rs`.
- Struct names are PascalCase: `UserService`, `CreateUserRequest`.
- Function names are snake_case: `create_user()`, `validate_email()`.
- Constants are SCREAMING_SNAKE_CASE: `MAX_REQUEST_SIZE`, `DEFAULT_TIMEOUT_MS`.
- Private functions and fields use leading underscore only in tests: `_helper_function()`.
- Type aliases for Result must be named `Result<T>` and defined in `src/errors.rs`: `pub type Result<T> = std::result::Result<T, AppError>`.
- Enum variants are PascalCase: `UserNotFound`, `InvalidEmail`, not `user_not_found`.
## Error Handling — Mandatory Patterns
- Define all application errors in `src/errors.rs` as a single enum `AppError` with variants for each error case.
- Every `AppError` variant must have a `message: String` field and a `status_code: u16` field.
- Never use `.unwrap()` or `.expect()` outside of `#[cfg(test)]` blocks.
- Never catch errors as `catch (e: any)` equivalent — use `match` on `Result<T, E>` with explicit error types.
- All functions that can fail must return `Result<T>` where `T` is the success type.
- Propagate errors with `?` operator — never convert errors silently.
- Database errors must be caught and converted to `AppError::DatabaseError(msg)` at the db layer, not in handlers.
- Validation errors must be caught and converted to `AppError::ValidationError(msg)` at the validation layer.
- HTTP handlers must return `Result<HttpResponse>` — Actix will convert `AppError` to HTTP response via `impl ResponseError for AppError`.
- Implement `impl ResponseError for AppError` to map each variant to correct HTTP status code and JSON body.
- Never log and return the same error — either log it or return it, not both.
## Async and Blocking Code
- Never call blocking operations (file I/O, CPU-intensive work, database queries) without `.spawn_blocking()`.
- All database queries must use `web::block()` or `tokio::task::spawn_blocking()` — never call sync database libraries directly in async context.
- Never use `std::thread::sleep()` — use `tokio::time::sleep()` instead.
- All futures must be `.await`ed — never fire-and-forget without explicit `tokio::spawn()`.
- Functions that call `.await` must be declared `async`.
- Never use `block_on()` in production code — only in `#[tokio::main]` or tests.
## Forbidden Patterns
- Never use `unsafe` without a comment explaining why it is necessary and what invariants it maintains.
- Never use `as` type casts for error handling — use `?` operator or explicit `match`.
- Never hardcode secrets, API keys, or database credentials in code — use environment variables loaded via `src/config.rs`.
- Never use `String` for structured data — use strongly-typed structs with `serde`.
- Never use `HashMap` or `BTreeMap` for configuration — use a typed struct.
- Never use `panic!()` in production code — return `Result<T>` instead.
- Never use `todo!()` or `unimplemented!()` in production code.
- Never ignore Clippy warnings — fix them or add `#[allow(clippy::...)]` with justification comment.
- Never use `#[allow(dead_code)]` without a comment explaining why the code exists.
- Never use `serde_json::json!()` macro in handlers — deserialize to typed structs instead.
- Never use `reqwest::Client::new()` in request handlers — inject a shared client via app state.
- Never use `tokio::time::timeout()` without a specific timeout value — define `TIMEOUT_MS` constant.
## Input Validation and Security
- All HTTP request bodies must be deserialized to typed structs with `serde`, never raw JSON.
- All path parameters must be validated before use — extract to typed struct with `web::Path<T>`.
- All query parameters must be validated before use — extract to typed struct with `web::Query<T>`.
- Validate email addresses with regex or a crate like `email_address` — never accept raw strings.
- Validate UUIDs with `uuid::Uuid::parse()` — never accept raw strings as IDs.
- Validate request body size with `web::JsonConfig::limit()` in `main.rs`.
- Never trust `Content-Length` header — validate actual payload size.
- Never log request bodies that contain passwords, tokens, or PII — sanitize before logging.
- All database queries must use parameterized queries — never string concatenation.
- All external API calls must validate response status codes before parsing body.
## Testing Conventions
- Test files live in `src/tests/` mirroring source structure: `src/tests/handlers/users.rs` tests `src/handlers/users.rs`.
- Integration tests live in `tests/` at project root: `tests/integration_users.rs`.
- Every test function must have `#[tokio::test]` attribute, not `#[test]`.
- Test names describe the scenario: `test_create_user_with_valid_email_succeeds()`, not `test_user()`.
- Every handler must have at least one happy-path test and one error-case test.
- Every error variant in `AppError` must have at least one test that triggers it.
- Mock external dependencies (HTTP clients, databases) — never hit real services in tests.
- Use `mockall` crate for mocking traits — never use `unsafe` mocks.
- Test database code with a real test database or `sqlx::query!()` compile-time checks.
- Never use `unwrap()` in test assertions — use `assert!()`, `assert_eq!()`, or `expect()` with message.
## Actix-web Specific Rules
- All routes must be defined in `src/main.rs` in a single `configure_routes()` function.
- Every route must have a name: `.route("/users", web::post().to(create_user).name("create_user"))`.
- All handlers must accept `web::Data<AppState>` as first parameter if they need shared state.
- Define `AppState` struct in `src/main.rs` with all shared dependencies (database pool, HTTP client).
- All middleware must be registered in `App::wrap()` in `src/main.rs`.
- Never use `web::scope()` without a prefix — always `.service(web::scope("/api/v1")...)`.
- All error responses must use `HttpResponse::*()` with explicit status codes: `HttpResponse::BadRequest().json()`.
- Never return raw strings from handlers — always return `HttpResponse` or `Result<HttpResponse>`.
## Clippy and Linting
- Run `cargo clippy --all-targets --all-features -- -D warnings` before every commit.
- Never suppress Clippy warnings with `#[allow(...)]` without a comment explaining why.
- Never use `#[allow(clippy::too_many_arguments)]` — refactor to accept a struct instead.
- Never use `#[allow(clippy::type_complexity)]` — extract complex types to type aliases.
- Fix all warnings in `cargo check` output before committing.
## Configuration and Secrets
- Load all configuration in `src/config.rs` at application startup.
- Use `dotenv` crate to load `.env` file in development only.
- Never commit `.env` file — add to `.gitignore`.
- All environment variables must have defaults or be marked as required with `panic!()` if missing.
- Store database connection strings in `DATABASE_URL` environment variable.
- Store API keys in `*_API_KEY` environment variables.
- Never log configuration values that contain secrets — sanitize before logging.
---
> Source: [Codelibrium](https://codelibrium.com) — the marketplace for AI behaviour files.
> Browse multiple rulesets at [codelibrium.com](https://codelibrium.com) or install via CLI:
> `npx codelibrium-cli install <ruleset-name>`