Skip to content

Commit 0de934a

Browse files
authored
Merge branch 'main' into docs-maintenance-2026-02-19-5439372498097529715
2 parents 9b74c6f + c55e34f commit 0de934a

File tree

9 files changed

+431
-80
lines changed

9 files changed

+431
-80
lines changed

docs/.agent/docs_coverage.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
# Docs Coverage Map
22

3-
| Feature | Documentation | Code Location | Status |
4-
|---------|---------------|---------------|--------|
3+
| Feature Area | Documentation Page | Source Code (Key Symbols) | Status |
4+
|--------------|-------------------|--------------------------|--------|
55
| **Core** | | | |
6-
| Routing | `concepts/handlers.md` | `rustapi-macros` | OK |
7-
| Extractors | `concepts/handlers.md` | `rustapi-core/src/extract.rs` | OK |
8-
| State | `concepts/handlers.md` | `rustapi-core/src/extract.rs` | OK |
9-
| Validation | `crates/rustapi_validate.md` | `rustapi-validate` | OK |
10-
| **HATEOAS** | | | |
11-
| Pagination | `recipes/pagination.md` | `rustapi-core/src/hateoas.rs` | OK |
12-
| Links | `recipes/pagination.md` | `rustapi-core/src/hateoas.rs` | OK |
6+
| Routing | `docs/cookbook/src/concepts/routing.md` | `rustapi-core/src/router.rs` (`Router`) | OK |
7+
| Handlers | `docs/cookbook/src/concepts/handlers.md` | `rustapi-core/src/handler.rs` (`Handler`) | OK |
8+
| Extractors | `docs/cookbook/src/concepts/extractors.md` | `rustapi-core/src/extract.rs` (`FromRequest`) | OK |
9+
| Middleware | `docs/cookbook/src/recipes/custom_middleware.md` | `rustapi-core/src/middleware/mod.rs` (`MiddlewareLayer`) | OK |
10+
| State | `docs/cookbook/src/concepts/state.md` | `rustapi-core/src/extract.rs` (`State`) | OK |
11+
| Error Handling | `docs/cookbook/src/concepts/errors.md` | `rustapi-core/src/error.rs` (`ApiError`) | OK |
12+
| HTTP/3 (QUIC) | `docs/cookbook/src/recipes/http3_quic.md` | `rustapi-core/src/http3.rs` (`Http3Server`) | OK |
13+
| File Uploads | `docs/cookbook/src/recipes/file_uploads.md` | `rustapi-core/src/multipart.rs` (`Multipart`) | OK |
14+
| Compression | `docs/cookbook/src/recipes/compression.md` | `rustapi-core/src/middleware/compression.rs` (`CompressionLayer`) | OK |
15+
| **OpenAPI** | | | |
16+
| Schema Derivation | `docs/cookbook/src/crates/rustapi_openapi.md` | `rustapi-macros/src/derive_schema.rs` (`#[derive(Schema)]`) | OK |
17+
| References ($ref) | `docs/cookbook/src/recipes/openapi_refs.md` | `rustapi-openapi/src/schema.rs` (`SchemaRef`) | OK |
18+
| **Validation** | | | |
19+
| Sync Validation | `docs/cookbook/src/crates/rustapi_validate.md` | `rustapi-validate/src/lib.rs` (`Validate`) | OK |
20+
| Async Validation | `docs/cookbook/src/crates/rustapi_validate.md` | `rustapi-validate/src/v2/mod.rs` (`AsyncValidate`) | OK |
1321
| **Extras** | | | |
1422
| Auth (JWT) | `recipes/jwt_auth.md` | `rustapi-extras/src/jwt` | OK |
1523
| Auth (OAuth2) | `recipes/oauth2_client.md` | `rustapi-extras/src/oauth2` | OK |
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Run Report: 2026-02-17
2+
3+
## Detected Version
4+
- **Target Version:** 0.1.335
5+
- **Commit:** (No new commits since last run)
6+
7+
## Changes
8+
No code changes detected. This run focused on documentation improvements and cookbook expansion.
9+
10+
## Documentation Updates
11+
12+
### Learning Path (`docs/cookbook/src/learning/curriculum.md`)
13+
- Added **Module 4.5: Database Integration** covering connection pooling with `sqlx`.
14+
- Added **Module 5.5: Error Handling** covering `ApiError` and production masking.
15+
- Added **Module 6.5: File Uploads & Multipart** covering streaming uploads.
16+
- Updated **Module 6: OpenAPI & HATEOAS** to include OpenAPI References.
17+
- Updated **Module 14: High Performance** to include Response Compression.
18+
19+
### Cookbook Recipes
20+
- **Created `recipes/compression.md`:** Detailed guide on using `CompressionLayer` with Gzip/Brotli/Deflate.
21+
- **Created `recipes/openapi_refs.md`:** Explanation of automatic `$ref` generation with `#[derive(Schema)]` and handling recursive types.
22+
- **Updated `recipes/file_uploads.md`:** Fixed body limit configuration (using `RustApi::new().body_limit(...)`), improved security notes, and added a complete example.
23+
- **Updated `recipes/db_integration.md`:** Expanded with production connection pool settings, transactions, and integration testing with `testcontainers`.
24+
25+
### Documentation Management
26+
- **Created `docs/.agent/docs_inventory.md`:** Full inventory of documentation files and their status.
27+
- **Created `docs/.agent/docs_coverage.md`:** Mapping of features to documentation pages.
28+
29+
## Improvements
30+
- Addressed user feedback regarding missing recipes for DB integration patterns, file uploads, error types, OpenAPI refs, and compression.
31+
- Standardized the Learning Path structure.
32+
33+
## TODOs
34+
- Verify `rustapi-grpc` examples with the latest `tonic` version.
35+
- Add a specific recipe for `rustapi-view` with HTMX.

docs/cookbook/src/SUMMARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
- [Part IV: Recipes](recipes/README.md)
3131
- [Creating Resources](recipes/crud_resource.md)
3232
- [Pagination & HATEOAS](recipes/pagination.md)
33+
- [OpenAPI & Schemas](recipes/openapi_refs.md)
3334
- [JWT Authentication](recipes/jwt_auth.md)
3435
- [OAuth2 Client](recipes/oauth2_client.md)
3536
- [CSRF Protection](recipes/csrf_protection.md)
@@ -43,6 +44,7 @@
4344
- [Server-Side Rendering (SSR)](recipes/server_side_rendering.md)
4445
- [AI Integration (TOON)](recipes/ai_integration.md)
4546
- [Production Tuning](recipes/high_performance.md)
47+
- [Response Compression](recipes/compression.md)
4648
- [Resilience Patterns](recipes/resilience.md)
4749
- [Audit Logging](recipes/audit_logging.md)
4850
- [Time-Travel Debugging (Replay)](recipes/replay.md)

docs/cookbook/src/learning/curriculum.md

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ Create a `POST /register` endpoint that accepts a JSON body `{"username": "...",
7878
2. Which extractor retrieves the application state?
7979
3. Why should you use `Arc` for shared state?
8080

81+
### Module 4.5: Database Integration
82+
- **Prerequisites:** Module 4.
83+
- **Reading:** [Database Integration](../recipes/db_integration.md).
84+
- **Task:** Replace the in-memory `Mutex<Vec<User>>` with a PostgreSQL connection pool (`sqlx::PgPool`).
85+
- **Expected Output:** Data persists across server restarts.
86+
- **Pitfalls:** Blocking the async runtime with synchronous DB drivers (use `sqlx` or `tokio-postgres`).
87+
88+
#### 🧠 Knowledge Check
89+
1. Why is connection pooling important?
90+
2. How do you share a DB pool across handlers?
91+
3. What is the benefit of compile-time query checking in SQLx?
92+
8193
### Module 5: Validation
8294
- **Prerequisites:** Module 4.
8395
- **Reading:** [Validation](../crates/rustapi_validation.md).
@@ -90,18 +102,42 @@ Create a `POST /register` endpoint that accepts a JSON body `{"username": "...",
90102
2. What HTTP status code is returned on validation failure?
91103
3. How do you combine JSON extraction and validation?
92104

105+
### Module 5.5: Error Handling
106+
- **Prerequisites:** Module 5.
107+
- **Reading:** [Error Handling](../concepts/errors.md).
108+
- **Task:** Create a custom `ApiError` enum and implement `IntoResponse`. Return robust error messages.
109+
- **Expected Output:** `GET /users/999` returns `404 Not Found` with a structured JSON error body.
110+
- **Pitfalls:** Exposing internal database errors (like SQL strings) to the client.
111+
112+
#### 🧠 Knowledge Check
113+
1. What is the standard error type in RustAPI?
114+
2. How do you mask internal errors in production?
115+
3. What is the purpose of the `error_id` field?
116+
93117
### Module 6: OpenAPI & HATEOAS
94118
- **Prerequisites:** Module 5.
95-
- **Reading:** [OpenAPI](../crates/rustapi_openapi.md), [Pagination Recipe](../recipes/pagination.md).
96-
- **Task:** Add `#[derive(Schema)]` to all DTOs. Implement pagination for `GET /users`.
97-
- **Expected Output:** Swagger UI at `/docs` showing full schema. Paginated responses with `_links`.
98-
- **Pitfalls:** Using types that don't implement `Schema` (like raw `serde_json::Value`) inside response structs.
119+
- **Reading:** [OpenAPI](../crates/rustapi_openapi.md), [OpenAPI Refs](../recipes/openapi_refs.md), [Pagination Recipe](../recipes/pagination.md).
120+
- **Task:** Add `#[derive(Schema)]` to all DTOs. Use `#[derive(Schema)]` on a shared struct and reference it in multiple places.
121+
- **Expected Output:** Swagger UI at `/docs` showing full schema with shared components.
122+
- **Pitfalls:** Recursive schemas without `Box` or `Option`.
99123

100124
#### 🧠 Knowledge Check
101125
1. What does `#[derive(Schema)]` do?
102-
2. Where is the Swagger UI served by default?
126+
2. How does RustAPI handle shared schema components?
103127
3. What is HATEOAS and why is it useful?
104128

129+
### Module 6.5: File Uploads & Multipart
130+
- **Prerequisites:** Module 6.
131+
- **Reading:** [File Uploads](../recipes/file_uploads.md).
132+
- **Task:** Create an endpoint `POST /upload` that accepts a file and saves it to disk.
133+
- **Expected Output:** `curl -F file=@image.png` uploads the file.
134+
- **Pitfalls:** Loading large files entirely into memory (use streaming).
135+
136+
#### 🧠 Knowledge Check
137+
1. Which extractor is used for file uploads?
138+
2. Why should you use `field.chunk()` instead of `field.bytes()`?
139+
3. How do you increase the request body size limit?
140+
105141
### 🏆 Phase 2 Capstone: "The Secure Blog Engine"
106142
**Objective:** Enhance the Todo API into a Blog Engine.
107143
**Requirements:**
@@ -233,18 +269,18 @@ Create a `POST /register` endpoint that accepts a JSON body `{"username": "...",
233269

234270
### Module 14: High Performance
235271
- **Prerequisites:** Phase 3.
236-
- **Reading:** [HTTP/3 (QUIC)](../recipes/http3_quic.md), [Performance Tuning](../recipes/high_performance.md).
272+
- **Reading:** [HTTP/3 (QUIC)](../recipes/http3_quic.md), [Performance Tuning](../recipes/high_performance.md), [Compression](../recipes/compression.md).
237273
- **Task:**
238274
1. Enable `http3` feature and generate self-signed certs.
239275
2. Serve traffic over QUIC.
240-
3. Implement response caching for a heavy computation endpoint.
241-
- **Expected Output:** Browser/Client connects via HTTP/3. Repeated requests are served instantly from cache.
242-
- **Pitfalls:** Caching private user data without proper keys.
276+
3. Add `CompressionLayer` to compress large responses.
277+
- **Expected Output:** Browser/Client connects via HTTP/3. Responses have `content-encoding: gzip`.
278+
- **Pitfalls:** Compressing small responses (waste of CPU) or already compressed data (images).
243279

244280
#### 🧠 Knowledge Check
245281
1. What transport protocol does HTTP/3 use?
246282
2. How does `simd-json` improve performance?
247-
3. When should you *not* use caching?
283+
3. Why shouldn't you compress JPEG images?
248284

249285
### 🏆 Phase 4 Capstone: "The High-Scale Event Platform"
250286
**Objective:** Architect a system capable of handling thousands of events per second.

docs/cookbook/src/recipes/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Each recipe follows a simple structure:
1313

1414
- [Creating Resources](crud_resource.md)
1515
- [Pagination & HATEOAS](pagination.md)
16+
- [OpenAPI & Schemas](openapi_refs.md)
1617
- [JWT Authentication](jwt_auth.md)
1718
- [CSRF Protection](csrf_protection.md)
1819
- [Database Integration](db_integration.md)
@@ -24,6 +25,7 @@ Each recipe follows a simple structure:
2425
- [Server-Side Rendering (SSR)](server_side_rendering.md)
2526
- [AI Integration (TOON)](ai_integration.md)
2627
- [Production Tuning](high_performance.md)
28+
- [Response Compression](compression.md)
2729
- [Resilience Patterns](resilience.md)
2830
- [Time-Travel Debugging (Replay)](replay.md)
2931
- [Deployment](deployment.md)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Response Compression
2+
3+
RustAPI supports automatic response compression (Gzip, Deflate, Brotli) via the `CompressionLayer`. This middleware negotiates the best compression algorithm based on the client's `Accept-Encoding` header.
4+
5+
## Dependencies
6+
7+
To use compression, you must enable the `compression` feature in `rustapi-core` (or `rustapi-rs`). For Brotli support, enable `compression-brotli`.
8+
9+
```toml
10+
[dependencies]
11+
rustapi-rs = { version = "0.1.335", features = ["compression", "compression-brotli"] }
12+
```
13+
14+
## Basic Usage
15+
16+
The simplest way to enable compression is to add the layer to your application:
17+
18+
```rust
19+
use rustapi_rs::prelude::*;
20+
use rustapi_core::middleware::CompressionLayer;
21+
22+
#[tokio::main]
23+
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
24+
RustApi::new()
25+
.layer(CompressionLayer::new())
26+
.route("/", get(hello))
27+
.run("127.0.0.1:8080")
28+
.await
29+
}
30+
31+
async fn hello() -> &'static str {
32+
"Hello, World! This response will be compressed if the client supports it."
33+
}
34+
```
35+
36+
## Configuration
37+
38+
You can customize the compression behavior using `CompressionConfig`:
39+
40+
```rust
41+
use rustapi_rs::prelude::*;
42+
use rustapi_core::middleware::{CompressionLayer, CompressionConfig};
43+
44+
#[tokio::main]
45+
async fn main() -> Result<()> {
46+
let config = CompressionConfig::new()
47+
.min_size(1024) // Only compress responses larger than 1KB
48+
.level(6) // Compression level (0-9)
49+
.gzip(true) // Enable Gzip
50+
.deflate(false) // Disable Deflate
51+
.brotli(true) // Enable Brotli (if feature enabled)
52+
.add_content_type("application/custom-json"); // Add custom type
53+
54+
RustApi::new()
55+
.layer(CompressionLayer::with_config(config))
56+
.route("/data", get(get_large_data))
57+
.run("127.0.0.1:8080")
58+
.await
59+
}
60+
```
61+
62+
## Default Configuration
63+
64+
By default, `CompressionLayer` is configured with:
65+
- `min_size`: 1024 bytes (1KB)
66+
- `level`: 6
67+
- `gzip`: enabled
68+
- `deflate`: enabled
69+
- `brotli`: enabled (if feature is present)
70+
- `content_types`: `text/*`, `application/json`, `application/javascript`, `application/xml`, `image/svg+xml`
71+
72+
## Best Practices
73+
74+
### 1. Don't Compress Already Compressed Data
75+
Images (JPEG, PNG), Videos, and Archives (ZIP) are already compressed. Compressing them again wastes CPU cycles and might even increase the file size. The default configuration excludes most binary formats, but be careful with custom types.
76+
77+
### 2. Set Minimum Size
78+
Compressing very small responses (e.g., "OK") can actually make them larger due to framing overhead. The default 1KB threshold is a good starting point.
79+
80+
### 3. Order of Middleware
81+
Compression should usually be one of the *last* layers added (outermost), so it compresses the final response after other middleware (like logging or headers) have run.
82+
83+
```rust
84+
RustApi::new()
85+
.layer(CompressionLayer::new()) // Runs last on response (first on request)
86+
.layer(LoggingLayer::new()) // Runs before compression on response
87+
```

0 commit comments

Comments
 (0)