3636 const path_to_root = "../" ;
3737 const default_light_theme = "light" ;
3838 const default_dark_theme = "navy" ;
39- window . path_to_searchindex_js = "../searchindex-6cf81054 .js" ;
39+ window . path_to_searchindex_js = "../searchindex-26942635 .js" ;
4040 </ script >
4141 <!-- Start loading toc.js asap -->
4242 < script src ="../toc-54f2b124.js "> </ script >
@@ -198,6 +198,10 @@ <h2 id="feature-flags"><a class="header" href="#feature-flags">Feature Flags</a>
198198< tr > < td > < code > audit</ code > </ td > < td > < code > AuditStore</ code > , < code > AuditLogger</ code > </ td > </ tr >
199199< tr > < td > < code > insight</ code > </ td > < td > < code > InsightLayer</ code > , < code > InsightStore</ code > </ td > </ tr >
200200< tr > < td > < code > rate-limit</ code > </ td > < td > < code > RateLimitLayer</ code > </ td > </ tr >
201+ < tr > < td > < code > replay</ code > </ td > < td > < code > ReplayLayer</ code > (Time-Travel Debugging)</ td > </ tr >
202+ < tr > < td > < code > timeout</ code > </ td > < td > < code > TimeoutLayer</ code > </ td > </ tr >
203+ < tr > < td > < code > guard</ code > </ td > < td > < code > PermissionGuard</ code > </ td > </ tr >
204+ < tr > < td > < code > sanitization</ code > </ td > < td > Input sanitization utilities</ td > </ tr >
201205</ tbody >
202206</ table >
203207</ div >
@@ -299,7 +303,7 @@ <h3 id="opentelemetry"><a class="header" href="#opentelemetry">OpenTelemetry</a>
299303 .layer(OtelLayer::new(config));
300304< span class ="boring "> }</ span > </ code > </ pre >
301305< h3 id ="structured-logging "> < a class ="header " href ="#structured-logging "> Structured Logging</ a > </ h3 >
302- < p > Emit logs as JSON for aggregators like Datadog or Splunk.</ p >
306+ < p > Emit logs as JSON for aggregators like Datadog or Splunk. This is different from request logging; it formats your application logs. </ p >
303307< pre class ="playground "> < code class ="language-rust "> < span class ="boring "> #![allow(unused)]
304308</ span > < span class ="boring "> fn main() {
305309</ span > use rustapi_extras::structured_logging::{StructuredLoggingLayer, JsonFormatter};
@@ -340,6 +344,29 @@ <h3 id="api-keys"><a class="header" href="#api-keys">API Keys</a></h3>
340344let app = RustApi::new()
341345 .layer(ApiKeyLayer::new("my-secret-key"));
342346< span class ="boring "> }</ span > </ code > </ pre >
347+ < h3 id ="permission-guards "> < a class ="header " href ="#permission-guards "> Permission Guards</ a > </ h3 >
348+ < p > The < code > guard</ code > feature provides role-based access control (RBAC) helpers.</ p >
349+ < pre class ="playground "> < code class ="language-rust "> < span class ="boring "> #![allow(unused)]
350+ </ span > < span class ="boring "> fn main() {
351+ </ span > use rustapi_extras::guard::PermissionGuard;
352+
353+ // Only allows users with "admin" role
354+ #[rustapi_rs::get("/admin")]
355+ async fn admin_panel(
356+ _guard: PermissionGuard
357+ ) -> &'static str {
358+ "Welcome Admin"
359+ }
360+ < span class ="boring "> }</ span > </ code > </ pre >
361+ < h3 id ="input-sanitization "> < a class ="header " href ="#input-sanitization "> Input Sanitization</ a > </ h3 >
362+ < p > The < code > sanitization</ code > feature helps prevent XSS by cleaning user input.</ p >
363+ < pre class ="playground "> < code class ="language-rust "> < span class ="boring "> #![allow(unused)]
364+ </ span > < span class ="boring "> fn main() {
365+ </ span > use rustapi_extras::sanitization::sanitize_html;
366+
367+ let safe_html = sanitize_html("<script>alert(1)</script>Hello");
368+ // Result: "&lt;script&gt;alert(1)&lt;/script&gt;Hello"
369+ < span class ="boring "> }</ span > </ code > </ pre >
343370< h2 id ="resilience "> < a class ="header " href ="#resilience "> Resilience</ a > </ h2 >
344371< h3 id ="circuit-breaker "> < a class ="header " href ="#circuit-breaker "> Circuit Breaker</ a > </ h3 >
345372< p > Prevent cascading failures by stopping requests to failing upstreams.</ p >
@@ -359,6 +386,16 @@ <h3 id="retry"><a class="header" href="#retry">Retry</a></h3>
359386let app = RustApi::new()
360387 .layer(RetryLayer::default());
361388< span class ="boring "> }</ span > </ code > </ pre >
389+ < h3 id ="timeout "> < a class ="header " href ="#timeout "> Timeout</ a > </ h3 >
390+ < p > Ensure requests don’t hang indefinitely.</ p >
391+ < pre class ="playground "> < code class ="language-rust "> < span class ="boring "> #![allow(unused)]
392+ </ span > < span class ="boring "> fn main() {
393+ </ span > use rustapi_extras::timeout::TimeoutLayer;
394+ use std::time::Duration;
395+
396+ let app = RustApi::new()
397+ .layer(TimeoutLayer::new(Duration::from_secs(30)));
398+ < span class ="boring "> }</ span > </ code > </ pre >
362399< h2 id ="optimization "> < a class ="header " href ="#optimization "> Optimization</ a > </ h2 >
363400< h3 id ="caching "> < a class ="header " href ="#caching "> Caching</ a > </ h3 >
364401< p > Cache responses based on headers or path.</ p >
@@ -378,6 +415,20 @@ <h3 id="request-deduplication"><a class="header" href="#request-deduplication">R
378415let app = RustApi::new()
379416 .layer(DedupLayer::new());
380417< span class ="boring "> }</ span > </ code > </ pre >
418+ < h2 id ="debugging "> < a class ="header " href ="#debugging "> Debugging</ a > </ h2 >
419+ < h3 id ="time-travel-debugging-replay "> < a class ="header " href ="#time-travel-debugging-replay "> Time-Travel Debugging (Replay)</ a > </ h3 >
420+ < p > The < code > replay</ code > feature allows you to record production traffic and replay it locally for debugging.</ p >
421+ < p > See the < a href ="../recipes/replay.html "> Time-Travel Debugging Recipe</ a > for full details.</ p >
422+ < pre class ="playground "> < code class ="language-rust "> < span class ="boring "> #![allow(unused)]
423+ </ span > < span class ="boring "> fn main() {
424+ </ span > use rustapi_extras::replay::{ReplayLayer, ReplayConfig, InMemoryReplayStore};
425+
426+ let replay_config = ReplayConfig::default();
427+ let store = InMemoryReplayStore::new(1_000);
428+
429+ let app = RustApi::new()
430+ .layer(ReplayLayer::new(replay_config).with_store(store));
431+ < span class ="boring "> }</ span > </ code > </ pre >
381432
382433 </ main >
383434
0 commit comments