From 1723f79e3eae5bd10b9456ee17d38b93ac868e15 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 03:53:09 +0000 Subject: [PATCH 1/6] docs: update cookbook for v0.1.300 and fix rustapi-jobs API Updated the cookbook documentation to align with the current codebase state (v0.1.300). Changes: - Fixed `rustapi-jobs` documentation: - Corrected `Job` trait implementation to use `execute` method instead of `run`. - Clarified the separation between Job handler and Job Data payload. - Updated enqueueing examples to pass data struct instead of handler struct. - Updated `rustapi-extras` documentation: - Added sections for `Replay` (Time-Travel Debugging), `Timeout`, `Sanitization`, and `Guard` features. - Clarified the distinction between request logging and structured logging. - Updated `rustapi-testing` documentation: - Added missing installation instructions. Co-authored-by: Tuntii <121901995+Tuntii@users.noreply.github.com> --- docs/cookbook/src/crates/rustapi_extras.md | 59 ++++++++++++++++++++- docs/cookbook/src/crates/rustapi_jobs.md | 35 +++++++----- docs/cookbook/src/crates/rustapi_testing.md | 9 ++++ 3 files changed, 88 insertions(+), 15 deletions(-) diff --git a/docs/cookbook/src/crates/rustapi_extras.md b/docs/cookbook/src/crates/rustapi_extras.md index 4d27b8b6..27334a6c 100644 --- a/docs/cookbook/src/crates/rustapi_extras.md +++ b/docs/cookbook/src/crates/rustapi_extras.md @@ -15,6 +15,9 @@ This crate is a collection of production-ready middleware. Everything is behind | `audit` | `AuditStore`, `AuditLogger` | | `insight` | `InsightLayer`, `InsightStore` | | `rate-limit` | `RateLimitLayer` | +| `replay` | `ReplayLayer` (Time-Travel Debugging) | +| `timeout` | `TimeoutLayer` | +| `guard` | `PermissionGuard` | ## Middleware Usage @@ -135,7 +138,7 @@ let app = RustApi::new() ### Structured Logging -Emit logs as JSON for aggregators like Datadog or Splunk. +Emit logs as JSON for aggregators like Datadog or Splunk. This is different from request logging; it formats your application logs. ```rust use rustapi_extras::structured_logging::{StructuredLoggingLayer, JsonFormatter}; @@ -184,6 +187,33 @@ let app = RustApi::new() .layer(ApiKeyLayer::new("my-secret-key")); ``` +### Permission Guards + +The `guard` feature provides role-based access control (RBAC) helpers. + +```rust +use rustapi_extras::guard::PermissionGuard; + +// Only allows users with "admin" role +#[rustapi_rs::get("/admin")] +async fn admin_panel( + _guard: PermissionGuard<"admin"> +) -> &'static str { + "Welcome Admin" +} +``` + +### Input Sanitization + +The `sanitization` feature helps prevent XSS by cleaning user input. + +```rust +use rustapi_extras::sanitization::sanitize_html; + +let safe_html = sanitize_html("Hello"); +// Result: "Hello" +``` + ## Resilience ### Circuit Breaker @@ -208,6 +238,18 @@ let app = RustApi::new() .layer(RetryLayer::default()); ``` +### Timeout + +Ensure requests don't hang indefinitely. + +```rust +use rustapi_extras::timeout::TimeoutLayer; +use std::time::Duration; + +let app = RustApi::new() + .layer(TimeoutLayer::new(Duration::from_secs(30))); +``` + ## Optimization ### Caching @@ -231,3 +273,18 @@ use rustapi_extras::dedup::DedupLayer; let app = RustApi::new() .layer(DedupLayer::new()); ``` + +## Debugging + +### Time-Travel Debugging (Replay) + +The `replay` feature allows you to record production traffic and replay it locally for debugging. + +See the [Time-Travel Debugging Recipe](../recipes/replay.md) for full details. + +```rust +use rustapi_extras::replay::{ReplayLayer, InMemoryReplayStore}; + +let app = RustApi::new() + .layer(ReplayLayer::new(InMemoryReplayStore::new())); +``` diff --git a/docs/cookbook/src/crates/rustapi_jobs.md b/docs/cookbook/src/crates/rustapi_jobs.md index 49f15057..fe81c7d4 100644 --- a/docs/cookbook/src/crates/rustapi_jobs.md +++ b/docs/cookbook/src/crates/rustapi_jobs.md @@ -11,29 +11,36 @@ Long-running tasks shouldn't block HTTP requests. `rustapi-jobs` provides a robu Here is how to set up a simple background job queue using the in-memory backend. -### 1. Define the Job +### 1. Define the Job and Data -Jobs are simple structs that implement `Serialize` and `Deserialize`. +Jobs are separated into two parts: +1. The **Data** struct (the payload), which must be serializable. +2. The **Job** struct (the handler), which contains the logic. ```rust use serde::{Deserialize, Serialize}; use rustapi_jobs::{Job, JobContext, Result}; -use std::sync::Arc; +use async_trait::async_trait; +// 1. The payload data #[derive(Serialize, Deserialize, Debug, Clone)] -struct EmailJob { +struct EmailJobData { to: String, subject: String, body: String, } -// Implement the Job trait to define how to process it -#[async_trait::async_trait] +// 2. The handler struct (usually stateless) +#[derive(Clone)] +struct EmailJob; + +#[async_trait] impl Job for EmailJob { const NAME: &'static str = "email_job"; + type Data = EmailJobData; - async fn run(&self, _ctx: JobContext) -> Result<()> { - println!("Sending email to {} with subject: {}", self.to, self.subject); + async fn execute(&self, _ctx: JobContext, data: Self::Data) -> Result<()> { + println!("Sending email to {} with subject: {}", data.to, data.subject); // Simulate work tokio::time::sleep(std::time::Duration::from_millis(100)).await; Ok(()) @@ -46,7 +53,7 @@ impl Job for EmailJob { In your `main` function, initialize the queue and start the worker. ```rust -use rustapi_jobs::{JobQueue, InMemoryBackend, EnqueueOptions}; +use rustapi_jobs::{JobQueue, InMemoryBackend}; #[tokio::main] async fn main() -> Result<(), Box> { @@ -56,17 +63,17 @@ async fn main() -> Result<(), Box> { // 2. Create the queue let queue = JobQueue::new(backend); - // 3. Register the job type - queue.register_job::(); + // 3. Register the job handler + queue.register_job(EmailJob).await; // 4. Start the worker in the background let worker_queue = queue.clone(); tokio::spawn(async move { - worker_queue.start_workers().await; + worker_queue.start_worker().await; }); - // 5. Enqueue a job - queue.enqueue(EmailJob { + // 5. Enqueue a job (pass the DATA, not the handler) + queue.enqueue::(EmailJobData { to: "user@example.com".into(), subject: "Welcome!".into(), body: "Thanks for joining.".into(), diff --git a/docs/cookbook/src/crates/rustapi_testing.md b/docs/cookbook/src/crates/rustapi_testing.md index b500dbd2..df410e64 100644 --- a/docs/cookbook/src/crates/rustapi_testing.md +++ b/docs/cookbook/src/crates/rustapi_testing.md @@ -7,6 +7,15 @@ 1. **In-process API testing**: Testing your endpoints without binding to a real TCP port. 2. **External service mocking**: Mocking downstream services (like payment gateways or auth providers) that your API calls. +## Installation + +Add the crate to your `dev-dependencies`: + +```toml +[dev-dependencies] +rustapi-testing = { version = "0.1.300" } +``` + ## The `TestClient` Integration testing is often slow and painful because it involves spinning up a server, waiting for ports, and managing child processes. `TestClient` solves this by wrapping your `RustApi` application and executing requests directly against the service layer. From 52b3ef812f1301883ddec52adfb6faafedfe8eef Mon Sep 17 00:00:00 2001 From: Tunay <121901995+Tuntii@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:16:00 +0300 Subject: [PATCH 2/6] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/cookbook/src/crates/rustapi_extras.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/cookbook/src/crates/rustapi_extras.md b/docs/cookbook/src/crates/rustapi_extras.md index 27334a6c..4121966c 100644 --- a/docs/cookbook/src/crates/rustapi_extras.md +++ b/docs/cookbook/src/crates/rustapi_extras.md @@ -283,8 +283,11 @@ The `replay` feature allows you to record production traffic and replay it local See the [Time-Travel Debugging Recipe](../recipes/replay.md) for full details. ```rust -use rustapi_extras::replay::{ReplayLayer, InMemoryReplayStore}; +use rustapi_extras::replay::{ReplayLayer, ReplayConfig, InMemoryReplayStore}; + +let replay_config = ReplayConfig::default(); +let store = InMemoryReplayStore::new(1_000); let app = RustApi::new() - .layer(ReplayLayer::new(InMemoryReplayStore::new())); + .layer(ReplayLayer::new(replay_config).with_store(store)); ``` From 7c92a2a9c5a51cbdbf6a72d8ec84d02bbc8af3b6 Mon Sep 17 00:00:00 2001 From: Tunay <121901995+Tuntii@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:16:09 +0300 Subject: [PATCH 3/6] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/cookbook/src/crates/rustapi_extras.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/cookbook/src/crates/rustapi_extras.md b/docs/cookbook/src/crates/rustapi_extras.md index 4121966c..5e39c377 100644 --- a/docs/cookbook/src/crates/rustapi_extras.md +++ b/docs/cookbook/src/crates/rustapi_extras.md @@ -18,6 +18,7 @@ This crate is a collection of production-ready middleware. Everything is behind | `replay` | `ReplayLayer` (Time-Travel Debugging) | | `timeout` | `TimeoutLayer` | | `guard` | `PermissionGuard` | +| `sanitization` | Input sanitization utilities | ## Middleware Usage From d73d62c3aacd701d8505ee1b5d455b9d9c4b62ca Mon Sep 17 00:00:00 2001 From: Tunay <121901995+Tuntii@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:16:19 +0300 Subject: [PATCH 4/6] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/cookbook/src/crates/rustapi_extras.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cookbook/src/crates/rustapi_extras.md b/docs/cookbook/src/crates/rustapi_extras.md index 5e39c377..218adb74 100644 --- a/docs/cookbook/src/crates/rustapi_extras.md +++ b/docs/cookbook/src/crates/rustapi_extras.md @@ -198,7 +198,7 @@ use rustapi_extras::guard::PermissionGuard; // Only allows users with "admin" role #[rustapi_rs::get("/admin")] async fn admin_panel( - _guard: PermissionGuard<"admin"> + _guard: PermissionGuard ) -> &'static str { "Welcome Admin" } From b670a337e5fb536f7761cab4ad0cb015c7c0e329 Mon Sep 17 00:00:00 2001 From: Tunay <121901995+Tuntii@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:16:49 +0300 Subject: [PATCH 5/6] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/cookbook/src/crates/rustapi_extras.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cookbook/src/crates/rustapi_extras.md b/docs/cookbook/src/crates/rustapi_extras.md index 218adb74..67a332a6 100644 --- a/docs/cookbook/src/crates/rustapi_extras.md +++ b/docs/cookbook/src/crates/rustapi_extras.md @@ -212,7 +212,7 @@ The `sanitization` feature helps prevent XSS by cleaning user input. use rustapi_extras::sanitization::sanitize_html; let safe_html = sanitize_html("Hello"); -// Result: "Hello" +// Result: "<script>alert(1)</script>Hello" ``` ## Resilience From 0bd0179f31da37b649af67ee85b683e00f43d44c Mon Sep 17 00:00:00 2001 From: Tunay <121901995+Tuntii@users.noreply.github.com> Date: Sun, 8 Feb 2026 18:17:10 +0300 Subject: [PATCH 6/6] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- docs/cookbook/src/crates/rustapi_jobs.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/cookbook/src/crates/rustapi_jobs.md b/docs/cookbook/src/crates/rustapi_jobs.md index fe81c7d4..21be0721 100644 --- a/docs/cookbook/src/crates/rustapi_jobs.md +++ b/docs/cookbook/src/crates/rustapi_jobs.md @@ -69,7 +69,9 @@ async fn main() -> Result<(), Box> { // 4. Start the worker in the background let worker_queue = queue.clone(); tokio::spawn(async move { - worker_queue.start_worker().await; + if let Err(e) = worker_queue.start_worker().await { + eprintln!("Worker failed: {:?}", e); + } }); // 5. Enqueue a job (pass the DATA, not the handler)