rust
51 lines · 7 steps
Feature-flag middleware in Axum
A shared, mutable flag set gates routes behind an async Axum middleware factory.
Explained by
highlit
1use std::{collections::HashSet, sync::Arc};
2
3use axum::{
4 body::Body,
5 extract::{Request, State},
6 http::StatusCode,
7 middleware::Next,
8 response::{IntoResponse, Response},
9};
10use tokio::sync::RwLock;
11
12#[derive(Clone, Default)]
13pub struct FeatureFlags {
14 enabled: Arc<RwLock<HashSet<String>>>,
15}
16
17impl FeatureFlags {
18 pub async fn is_enabled(&self, flag: &str) -> bool {
19 self.enabled.read().await.contains(flag)
20 }
21
22 pub async fn set(&self, flag: &str, on: bool) {
23 let mut guard = self.enabled.write().await;
24 if on {
25 guard.insert(flag.to_owned());
26 } else {
27 guard.remove(flag);
28 }
29 }
30}
31
32pub fn require_flag(
33 flag: &'static str,
34) -> impl Clone + Fn(State<FeatureFlags>, Request, Next) -> BoxedFuture {
35 move |State(flags): State<FeatureFlags>, req: Request, next: Next| {
36 Box::pin(async move {
37 if flags.is_enabled(flag).await {
38 next.run(req).await
39 } else {
40 (
41 StatusCode::NOT_FOUND,
42 format!("feature `{flag}` is not available"),
43 )
44 .into_response()
45 }
46 })
47 }
48}
49
50type BoxedFuture =
51 std::pin::Pin<Box<dyn std::future::Future<Output = Response<Body>> + Send>>;
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1An Arc<RwLock<...>> lets many handlers read shared state concurrently while still allowing exclusive updates.
- 2Returning a closure from a function lets you parameterize middleware — here, per-flag gating — while keeping one implementation.
- 3Axum middleware can either forward the request via next.run or short-circuit with its own response.
Related explainers
rust
use serde::Deserialize; #[derive(Debug, Deserialize)] #[serde(untagged)]
Parsing flexible JSON shapes with serde
deserialization
enums
json
Intermediate
6 steps
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
rust
use std::cmp::{Ordering, Reverse}; use std::collections::BinaryHeap; use std::fs::File; use std::io::{self, BufRead, BufReader, BufWriter, Lines, Write};
K-way merge of sorted logs in Rust
binary-heap
k-way-merge
streaming-io
Intermediate
8 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
javascript
function evaluate(expression) { const tokens = tokenize(expression); let pos = 0;
Building a recursive descent calculator
parsing
recursion
operator-precedence
Intermediate
8 steps
rust
use axum::{ extract::{Path, State}, response::sse::{Event, KeepAlive, Sse}, };
Streaming import progress with SSE in Axum
server-sent-events
streams
watch-channel
Advanced
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/feature-flag-middleware-in-axum-explained-rust-a54d/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.