tower-request-guard
Request validation middleware for Tower.
Every API needs input validation before the handler runs. tower-request-guard replaces 3-4 separate Tower layers with a single configurable middleware: body size limits, timeouts, content-type enforcement, required headers, and JSON depth protection.
Features
- Max body size — Reject oversized payloads via Content-Length pre-check
- Per-route timeout — 504 Gateway Timeout with configurable duration per route
- Content-Type validation — Media type matching with charset/parameter tolerance
- Required headers — Enforce N headers (Authorization, X-Request-Id, etc.)
- JSON depth protection — Anti-JSON-bomb via max nesting depth (feature
json) - Per-route overrides — Override any setting per route with
route_guard - Dry-run mode —
LogAndPasslogs violations without rejecting (gradual migration) - Custom violation handler — Full control with
OnViolation::custom() - Bodyless method skip — GET/HEAD/DELETE/OPTIONS skip body checks automatically
- Tower-native — Works with Axum, Tonic, Hyper, or any Tower-based framework
Quick Start
Add to your Cargo.toml:
[]
= "0.1"
Configure the Guard
use ;
use Duration;
use RequestGuard;
let guard = builder
.max_body_size // 1 MB
.timeout // 30s
.allowed_content_types // JSON only
.require_header
.build;
let app = new
.route
.layer;
Per-Route Overrides
Use route_guard to override global settings for specific routes. Apply it as the outer layer relative to the guard — it inserts config into request extensions before the guard reads them.
In Axum, use separate sub-routers and merge them:
use ;
let guard_layer = guard.layer; // Arc inside, cheap to clone
// Standard routes — global guard applies as-is
let api = new
.route
.layer;
// Upload — larger limits, different content type, no auth
let upload = new
.route
.layer // inner: validates
.layer;
// Health — skip all validations
let health = new
.route
.layer
.layer;
let app = api.merge.merge;
OnViolation Policies
Control what happens when a violation is detected:
use ;
// Reject (default) — returns appropriate 4xx/5xx immediately
.on_violation
// Log and pass — dry-run mode for gradual migration
.on_violation
// Custom — full control with callback
.on_violation
JSON Depth Protection
Enable the json feature for anti-JSON-bomb protection:
= { = "0.1", = ["json"] }
use ;
let guard = builder
.max_json_depth // max nesting depth
.max_body_size // also checked post-buffering
.build;
let layer = new;
The buffered variant reads the full body, checks size, validates JSON depth, then forwards the request with a Full<Bytes> body.
Violation Responses
Each violation returns a JSON body with context:
| Violation | Status | Error Key |
|---|---|---|
| Body exceeds max size | 413 Payload Too Large | body_too_large |
| Timeout expired | 504 Gateway Timeout | request_timeout |
| Content-Type not allowed | 415 Unsupported Media Type | invalid_content_type |
| Required header missing | 400 Bad Request | missing_header |
| JSON depth exceeded | 400 Bad Request | json_too_deep |
| Malformed JSON | 400 Bad Request | invalid_json |
Example response:
Feature Flags
| Feature | Default | Description |
|---|---|---|
json |
No | JSON depth validation via serde_json + body buffering via http-body-util |
Comparison
| Feature | tower-http (multiple layers) | tower-request-guard |
|---|---|---|
| Max body size | RequestBodyLimitLayer |
Yes |
| Per-route timeout | TimeoutLayer (global only) |
Yes |
| Content-Type validation | No | Yes (media type matching) |
| Required headers (N) | ValidateRequestHeader (1) |
Yes |
| JSON depth (anti bomb) | No | Yes (feature json) |
| All in one layer | No (3-4 separate layers) | Yes |
| Per-route overrides | No | Yes (route_guard) |
| Dry-run mode | No | Yes (LogAndPass) |
| Bodyless method skip | Manual | Automatic |
| Custom violation handler | No | Yes (OnViolation::Custom) |
Examples
See the examples/ directory:
axum_basic.rs— Simple global guard with Axumaxum_routes.rs— Per-route overrides using sub-router + merge patternaxum_migration.rs— LogAndPass dry-run mode with tracing
Companion Crate
tower-rate-tier — Tier-based rate limiting middleware for Tower.
Together: rate-tier controls how many times you can call, request-guard validates what you send is correct and safe.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.