actix-web-extras
A small Rust crate that adds a Condition middleware to actix-web, letting you enable or disable any other middleware at runtime.
Repository Health
Technical Analysis
actix-web-extras exists to fill one narrow gap in actix-web’s built-in middleware set: the ability to conditionally enable or disable a wrapped middleware without changing the shape of your .wrap() chain. Its single exported type, Condition<T>, takes a boolean flag or an Option<T> and produces a Transform that either runs the inner middleware or passes the request straight through, unifying the two possible response types with actix-web’s EitherBody.
The crate is intentionally minimal — one module, one struct, no macros, no extra dependencies beyond actix-web, futures-core, futures-util, and pin-project-lite. It targets a specific pain point (toggling Logger, Compress, NormalizePath, DefaultHeaders, or custom ErrorHandlers based on an environment variable or config flag) rather than trying to be a general-purpose extension pack, despite the broader ambition suggested by its name.
What You Get
- A
Condition<T>struct implementing actix-web’sTransformandServicetraits for any wrapped middleware typeT - Two constructors:
Condition::new(bool, transformer)for flag-based toggling andCondition::from_option(Option<transformer>)for building directly from optional config - Response body unification via actix-web’s
EitherBody, so the enabled and disabled code paths type-check as a singleServiceimplementation - Drop-in compatibility with actix-web’s own middleware (
Logger,Compress,NormalizePath,DefaultHeaders,ErrorHandlers) with no changes required on their side
Common Use Cases
- Environment-gated middleware - an operator enables
NormalizePathonly when aNORMALIZE_PATHenv var is set, without branching theApp::new()construction code itself - Config-driven feature toggles - a service enables or disables custom
ErrorHandlersorCompressbased on anOption<T>field already present in its config struct - Test vs. production middleware stacks - a test build disables logging or compression middleware while keeping an identical
.wrap()chain shape to production - Gradual middleware rollout - a team wraps a new middleware in
Conditionbehind a flag so it can be flipped on for a subset of environments before full adoption
Under The Hood
Architecture
The crate is a single-module library exposing one middleware type, Condition<T>, under middleware::. It implements actix-web’s Transform/Service trait pair, holding an Option<T> set once at construction. new_transform branches exactly once — at app-build time, not per request — into a boxed future that either drives the wrapped transformer’s own new_transform and returns ConditionMiddleware::Enable, or immediately resolves to ConditionMiddleware::Disable. Per-request dispatch matches on that two-armed enum in poll_ready/call, and a pin_project!-generated ConditionMiddlewareFuture enum mirrors the same structure so no dynamic dispatch or extra allocation happens on the hot path. There is effectively one abstraction in the whole crate — changing it means rewriting the crate.
Tech Stack
Pure Rust (edition 2018) built directly against actix-web 4’s Transform, Service, and EitherBody primitives with no wrapper crates in between. futures-core/futures-util supply LocalBoxFuture and FutureExt::boxed_local; pin-project-lite’s pin_project! macro safely projects the two-armed future enum without unsafe code. Dev-dependencies (actix-service, actix-rt) are used only inside the test module to build an actix_web::test harness — there is no build tooling beyond Cargo and no framework layer beyond actix-web itself.
Code Quality
The crate ships a real test module exercising all four branches (enabled/disabled × new/from_option) against actix-web’s own test::call_service harness, asserting header side effects to confirm the correct middleware path ran. Error handling stays generic over the wrapped middleware’s own Err type rather than introducing a new error type, so failures propagate unchanged. Naming mirrors actix-web’s own middleware conventions (Condition, ConditionMiddleware, ConditionMiddlewareFuture), the public API is fully typed with no unsafe blocks, but no CI configuration or linter config ships in the repo beyond an inline clippy allow attribute in the tests.
API Design
One import path (actix_web_extras::middleware::Condition) and two constructors covering the two natural entry points — a bool flag or an Option — compose with .wrap() exactly like any other actix-web middleware, requiring no new mental model beyond “you’re wrapping a wrapper.” Doc comments carry runnable examples for both constructors directly in the source, which is the entire public documentation surface; there is no separate docs site or guide beyond a one-line README.