Skip to content

Commit 1e235e7

Browse files
authored
Merge pull request #129 from Tuntii/docs-maintenance-2026-02-19-5439372498097529715
docs: continuous improvement and accuracy fixes
2 parents c55e34f + 0de934a commit 1e235e7

File tree

10 files changed

+123
-213
lines changed

10 files changed

+123
-213
lines changed

docs/.agent/docs_coverage.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,23 @@
1919
| Sync Validation | `docs/cookbook/src/crates/rustapi_validate.md` | `rustapi-validate/src/lib.rs` (`Validate`) | OK |
2020
| Async Validation | `docs/cookbook/src/crates/rustapi_validate.md` | `rustapi-validate/src/v2/mod.rs` (`AsyncValidate`) | OK |
2121
| **Extras** | | | |
22-
| JWT Auth | `docs/cookbook/src/recipes/jwt_auth.md` | `rustapi-extras/src/jwt.rs` (`JwtLayer`) | OK |
23-
| OAuth2 | `docs/cookbook/src/recipes/oauth2_client.md` | `rustapi-extras/src/oauth2.rs` (`OAuth2Client`) | OK |
24-
| Database | `docs/cookbook/src/recipes/db_integration.md` | N/A (Integration pattern) | Needs Update |
25-
| **Ecosystem** | | | |
26-
| WebSockets | `docs/cookbook/src/recipes/websockets.md` | `rustapi-ws/src/lib.rs` (`WebSocketUpgrade`) | OK |
27-
| SSR (View) | `docs/cookbook/src/recipes/server_side_rendering.md` | `rustapi-view/src/lib.rs` (`View`) | OK |
28-
| gRPC | `docs/cookbook/src/recipes/grpc_integration.md` | `rustapi-grpc/src/lib.rs` (`TonicServer`) | OK |
29-
| Jobs | `docs/cookbook/src/recipes/background_jobs.md` | `rustapi-jobs/src/lib.rs` (`Job`) | OK |
30-
| TOON (AI) | `docs/cookbook/src/recipes/ai_integration.md` | `rustapi-toon/src/lib.rs` (`LlmResponse`) | OK |
22+
| Auth (JWT) | `recipes/jwt_auth.md` | `rustapi-extras/src/jwt` | OK |
23+
| Auth (OAuth2) | `recipes/oauth2_client.md` | `rustapi-extras/src/oauth2` | OK |
24+
| Security | `recipes/csrf_protection.md` | `rustapi-extras/src/security` | OK |
25+
| Observability | `crates/rustapi_extras.md` | `rustapi-extras/src/telemetry` | OK |
26+
| Audit Logging | `recipes/audit_logging.md` | `rustapi-extras/src/audit` | OK |
27+
| Middleware (Advanced) | `recipes/advanced_middleware.md` | `rustapi-extras/src/{rate_limit, dedup, cache}` | OK |
28+
| **Jobs** | | | |
29+
| Job Queue (Crate) | `crates/rustapi_jobs.md` | `rustapi-jobs` | OK |
30+
| Background Jobs (Recipe) | `recipes/background_jobs.md` | `rustapi-jobs` | OK |
31+
| **Integrations** | | | |
32+
| gRPC | `recipes/grpc_integration.md` | `rustapi-grpc` | OK |
33+
| SSR | `recipes/server_side_rendering.md` | `rustapi-view` | OK |
34+
| AI / TOON | `recipes/ai_integration.md` | `rustapi-toon` | OK |
35+
| WebSockets | `recipes/websockets.md` | `rustapi-ws` | Updated |
36+
| **Learning** | | | |
37+
| Structured Path | `learning/curriculum.md` | N/A | Updated (Mini Projects) |
38+
| **Recipes** | | | |
39+
| File Uploads | `recipes/file_uploads.md` | `rustapi-core` | Updated (Buffered) |
40+
| Deployment | `recipes/deployment.md` | `cargo-rustapi` | OK |
41+
| Testing | `recipes/testing.md` | `rustapi-testing` | OK |

docs/.agent/docs_inventory.md

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,16 @@
11
# Documentation Inventory
22

3-
| File Path | Purpose | Last Updated Version | Owner Crate | Status |
4-
|-----------|---------|----------------------|-------------|--------|
5-
| `docs/README.md` | Main entry point | 0.1.335 | rustapi-rs | OK |
6-
| `docs/GETTING_STARTED.md` | Quick start guide | 0.1.335 | rustapi-rs | OK |
7-
| `docs/ARCHITECTURE.md` | High-level architecture | 0.1.335 | rustapi-core | OK |
8-
| `docs/FEATURES.md` | Feature list | 0.1.335 | rustapi-rs | OK |
9-
| `docs/PHILOSOPHY.md` | Design philosophy | 0.1.335 | rustapi-rs | OK |
10-
| `docs/native_openapi.md` | Native OpenAPI details | 0.1.335 | rustapi-openapi | OK |
11-
| `docs/cookbook/src/SUMMARY.md` | Cookbook ToC | 0.1.335 | rustapi-rs | Needs Update |
12-
| `docs/cookbook/src/introduction.md` | Cookbook Intro | 0.1.335 | rustapi-rs | OK |
13-
| `docs/cookbook/src/troubleshooting.md` | Common issues | 0.1.335 | rustapi-rs | OK |
14-
| `docs/cookbook/src/learning/curriculum.md` | Learning Path | 0.1.335 | rustapi-rs | Needs Update |
15-
| `docs/cookbook/src/recipes/db_integration.md` | Database recipe | 0.1.335 | rustapi-rs | Needs Update |
16-
| `docs/cookbook/src/recipes/file_uploads.md` | File upload recipe | 0.1.335 | rustapi-core | OK |
17-
| `docs/cookbook/src/recipes/compression.md` | Compression recipe | 0.1.335 | rustapi-core | OK |
18-
| `docs/cookbook/src/recipes/openapi_refs.md` | OpenAPI Refs recipe | 0.1.335 | rustapi-openapi | OK |
19-
| `docs/cookbook/src/recipes/http3_quic.md` | HTTP/3 recipe | 0.1.335 | rustapi-core | OK |
20-
| `docs/cookbook/src/recipes/jwt_auth.md` | JWT Auth recipe | 0.1.335 | rustapi-extras | OK |
21-
| `docs/cookbook/src/recipes/websockets.md` | WebSocket recipe | 0.1.335 | rustapi-ws | OK |
22-
| `docs/cookbook/src/recipes/server_side_rendering.md` | SSR recipe | 0.1.335 | rustapi-view | OK |
23-
| `docs/cookbook/src/recipes/grpc_integration.md` | gRPC recipe | 0.1.335 | rustapi-grpc | OK |
24-
| `docs/cookbook/src/recipes/background_jobs.md` | Jobs recipe | 0.1.335 | rustapi-jobs | OK |
25-
| `docs/cookbook/src/recipes/ai_integration.md` | AI/TOON recipe | 0.1.335 | rustapi-toon | OK |
3+
| File | Purpose | Owner Crate | Status |
4+
|------|---------|-------------|--------|
5+
| `README.md` | Project overview, key features, quick start | Root | OK |
6+
| `docs/README.md` | Documentation landing page | Docs | OK |
7+
| `docs/cookbook/src/SUMMARY.md` | Cookbook navigation structure | Docs | OK |
8+
| `docs/cookbook/src/learning/curriculum.md` | Structured learning path | Docs | Updated (Mini Projects) |
9+
| `docs/cookbook/src/recipes/file_uploads.md` | Recipe for File Uploads | Docs | Updated (Buffered) |
10+
| `docs/cookbook/src/recipes/websockets.md` | Recipe for Real-time Chat | Docs | Updated (Extractors) |
11+
| `docs/cookbook/src/recipes/background_jobs.md` | Recipe for Background Jobs | Docs | OK |
12+
| `docs/cookbook/src/recipes/tuning.md` | Performance Tuning | Docs | DELETED |
13+
| `docs/cookbook/src/recipes/new_feature.md` | New Feature Guide | Docs | DELETED |
14+
| `docs/cookbook/src/architecture/action_pattern.md` | Action Pattern Guide | Docs | DELETED |
15+
| `crates/rustapi-core/src/hateoas.rs` | API Reference for HATEOAS | rustapi-core | OK |
16+
| `crates/rustapi-core/src/extract.rs` | API Reference for Extractors | rustapi-core | OK |

docs/.agent/last_run.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"last_processed_ref": "v0.1.335",
3-
"date": "2026-02-17",
4-
"notes": "Added recipes for Compression, OpenAPI Refs, File Uploads, and Database Integration. Updated Learning Path with new modules."
3+
"date": "2026-02-19",
4+
"notes": "Deleted incorrect recipes (tuning, action pattern). Updated File Uploads and WebSockets recipes for accuracy. Expanded Learning Path with mini projects."
55
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Run Report: 2026-02-19
2+
3+
## Summary
4+
Performed a continuous improvement pass on the documentation, focusing on accuracy in recipes and expanding the learning path.
5+
6+
## Version Detection
7+
- **Version**: 0.1.335
8+
- **Status**: No new version detected. Maintenance mode.
9+
10+
## Changes
11+
### 🗑️ Deleted Orphaned/Incorrect Files
12+
- `docs/cookbook/src/recipes/tuning.md`: Referenced non-existent benchmark scripts.
13+
- `docs/cookbook/src/recipes/new_feature.md`: Described non-existent "Action Pattern".
14+
- `docs/cookbook/src/architecture/action_pattern.md`: Described non-existent "Action Pattern".
15+
16+
### 📝 Updated Recipes
17+
- **File Uploads** (`docs/cookbook/src/recipes/file_uploads.md`):
18+
- Removed incorrect claims about streaming support in `Multipart`.
19+
- Updated example to correctly use buffered `field.bytes()` and `field.save_to()`.
20+
- Added warning about memory usage and `DefaultBodyLimit`.
21+
- **WebSockets** (`docs/cookbook/src/recipes/websockets.md`):
22+
- Corrected `ws_handler` signature to use `WebSocket` extractor instead of `WebSocketUpgrade`.
23+
- Corrected `handle_socket` signature to accept `WebSocketStream`.
24+
- Fixed imports and usage of `StreamExt`.
25+
26+
### 📚 Learning Path
27+
- **Curriculum** (`docs/cookbook/src/learning/curriculum.md`):
28+
- Added "Mini Projects" to Module 1 (Echo Server), Module 2 (Calculator), and Module 3 (User Registry) to encourage hands-on practice.
29+
30+
## TODOs
31+
- Verify if `rustapi-core` plans to support streaming multipart in the future.
32+
- Review other recipes for similar inaccuracies.

docs/cookbook/src/architecture/action_pattern.md

Lines changed: 0 additions & 39 deletions
This file was deleted.

docs/cookbook/src/learning/curriculum.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ This curriculum is designed to take you from a RustAPI beginner to an advanced u
1313
- **Expected Output:** A running server that responds to `GET /` with "Hello World".
1414
- **Pitfalls:** Not enabling `tokio` features if setting up manually.
1515

16+
#### 🛠️ Mini Project: "The Echo Server"
17+
Create a new endpoint `POST /echo` that accepts any text body and returns it back to the client. This verifies your setup handles basic I/O correctly.
18+
1619
#### 🧠 Knowledge Check
1720
1. What command scaffolds a new RustAPI project?
1821
2. Which feature flag is required for the async runtime?
@@ -25,6 +28,9 @@ This curriculum is designed to take you from a RustAPI beginner to an advanced u
2528
- **Expected Output:** Endpoints that return static JSON data.
2629
- **Pitfalls:** Forgetting to register routes in `main.rs` if not using auto-discovery.
2730

31+
#### 🛠️ Mini Project: "The Calculator"
32+
Create an endpoint `GET /add?a=5&b=10` that returns `{"result": 15}`. This practices query parameter extraction and JSON responses.
33+
2834
#### 🧠 Knowledge Check
2935
1. Which macro is used to define a GET handler?
3036
2. How do you return a JSON response from a handler?
@@ -37,6 +43,9 @@ This curriculum is designed to take you from a RustAPI beginner to an advanced u
3743
- **Expected Output:** `GET /users/{id}` returns the ID. `POST /users` echoes the JSON body.
3844
- **Pitfalls:** Consuming the body twice (e.g., using `Json` and `Body` in the same handler).
3945

46+
#### 🛠️ Mini Project: "The User Registry"
47+
Create a `POST /register` endpoint that accepts a JSON body `{"username": "...", "age": ...}` and returns a welcome message using the username. Use the `Json` extractor.
48+
4049
#### 🧠 Knowledge Check
4150
1. Which extractor is used for URL parameters like `/users/:id`?
4251
2. Which extractor parses the request body as JSON?

docs/cookbook/src/recipes/file_uploads.md

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# File Uploads
22

3-
Handling file uploads efficiently is crucial for modern applications. RustAPI provides a `Multipart` extractor that allows you to stream uploads, enabling you to handle large files (e.g., 1GB+) without consuming proportional RAM.
3+
Handling file uploads is a common requirement. RustAPI provides a `Multipart` extractor to parse `multipart/form-data` requests.
44

55
## Dependencies
66

@@ -13,15 +13,13 @@ tokio = { version = "1", features = ["fs", "io-util"] }
1313
uuid = { version = "1", features = ["v4"] }
1414
```
1515

16-
## Streaming Upload Example
16+
## Buffered Upload Example
1717

18-
Here is a complete, runnable example of a file upload server that streams files to a `./uploads` directory.
18+
RustAPI's `Multipart` extractor currently buffers the entire request body into memory before parsing. This means it is suitable for small to medium file uploads (e.g., images, documents) but care must be taken with very large files to avoid running out of RAM.
1919

2020
```rust
2121
use rustapi_rs::prelude::*;
22-
use rustapi_core::multipart::Multipart;
23-
use tokio::fs::File;
24-
use tokio::io::AsyncWriteExt;
22+
use rustapi_rs::extract::{Multipart, DefaultBodyLimit};
2523
use std::path::Path;
2624

2725
#[tokio::main]
@@ -35,6 +33,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
3533
// Increase body limit to 1GB (default is usually 1MB)
3634
.body_limit(1024 * 1024 * 1024)
3735
.route("/upload", post(upload_handler))
36+
// Increase body limit to 50MB (default is usually 2MB)
37+
// ⚠️ IMPORTANT: Since Multipart buffers the whole body,
38+
// setting this too high can exhaust server memory.
39+
.layer(DefaultBodyLimit::max(50 * 1024 * 1024))
3840
.run("127.0.0.1:8080")
3941
.await
4042
}
@@ -56,27 +58,31 @@ async fn upload_handler(mut multipart: Multipart) -> Result<Json<UploadResponse>
5658
let mut uploaded_files = Vec::new();
5759

5860
// Iterate over the fields in the multipart form
59-
while let Some(mut field) = multipart.next_field().await.map_err(|_| ApiError::bad_request("Invalid multipart"))? {
61+
while let Some(field) = multipart.next_field().await.map_err(|_| ApiError::bad_request("Invalid multipart"))? {
6062

63+
// Skip fields that are not files
64+
if !field.is_file() {
65+
continue;
66+
}
67+
6168
let file_name = field.file_name().unwrap_or("unknown.bin").to_string();
6269
let content_type = field.content_type().unwrap_or("application/octet-stream").to_string();
6370

6471
// ⚠️ Security: Never trust the user-provided filename directly!
6572
// It could contain paths like "../../../etc/passwd".
6673
// Always generate a safe filename or sanitize inputs.
6774
let safe_filename = format!("{}-{}", uuid::Uuid::new_v4(), file_name);
68-
let path = Path::new("./uploads").join(&safe_filename);
6975

70-
println!("Streaming file: {} -> {:?}", file_name, path);
76+
// Option 1: Use the helper method (sanitizes filename automatically)
77+
// field.save_to("./uploads", Some(&safe_filename)).await.map_err(|e| ApiError::internal(e.to_string()))?;
7178

72-
// Open destination file
73-
let mut file = File::create(&path).await.map_err(|e| ApiError::internal(e.to_string()))?;
79+
// Option 2: Manual write (gives you full control)
80+
let data = field.bytes().await.map_err(|e| ApiError::internal(e.to_string()))?;
81+
let path = Path::new("./uploads").join(&safe_filename);
7482

75-
// Stream the field content chunk-by-chunk
76-
// This is memory efficient even for large files.
77-
while let Some(chunk) = field.chunk().await.map_err(|_| ApiError::bad_request("Stream error"))? {
78-
file.write_all(&chunk).await.map_err(|e| ApiError::internal(e.to_string()))?;
79-
}
83+
tokio::fs::write(&path, &data).await.map_err(|e| ApiError::internal(e.to_string()))?;
84+
85+
println!("Saved file: {} -> {:?}", file_name, path);
8086

8187
uploaded_files.push(FileResult {
8288
original_name: file_name,
@@ -94,13 +100,14 @@ async fn upload_handler(mut multipart: Multipart) -> Result<Json<UploadResponse>
94100

95101
## Key Concepts
96102

97-
### 1. Streaming vs Buffering
98-
By default, some frameworks load the entire file into RAM. RustAPI's `Multipart` allows you to process the stream incrementally using `field.chunk()`.
99-
- **Buffering**: `field.bytes().await` (Load all into RAM - simple but dangerous for large files)
100-
- **Streaming**: `field.chunk().await` (Load small chunks - scalable)
103+
### 1. Buffering
104+
RustAPI loads the entire `multipart/form-data` body into memory.
105+
- **Pros**: Simple API, easy to work with.
106+
- **Cons**: High memory usage for concurrent large uploads.
107+
- **Mitigation**: Set a reasonable `DefaultBodyLimit` (e.g., 10MB - 100MB) to prevent DoS attacks.
101108

102109
### 2. Body Limits
103-
The default request body limit is often small (e.g., 1MB) to prevent DoS attacks. You must explicitly increase this limit for file upload routes using `RustApi::new().body_limit(size)`. This applies globally to the application instance. If you need different limits for different routes, consider creating separate router instances or using a custom layer.
110+
The default request body limit is small (2MB) to prevent attacks. You **must** explicitly increase this limit for file upload routes using `.layer(DefaultBodyLimit::max(size_in_bytes))`.
104111

105112
### 3. Security
106113
- **Path Traversal**: Malicious users can send filenames like `../../system32/cmd.exe`. Always rename files or sanitize filenames strictly.

docs/cookbook/src/recipes/new_feature.md

Lines changed: 0 additions & 73 deletions
This file was deleted.

docs/cookbook/src/recipes/tuning.md

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)