python
39 lines · 7 steps
Gating a FastAPI route behind a feature flag
A dependency factory builds a per-flag guard that hides experimental endpoints from users who lack access.
Explained by
highlit
1from fastapi import APIRouter, Depends, HTTPException, status
2
3from app.config import settings
4from app.dependencies import get_current_user
5from app.models import User
6from app.schemas import RecommendationOut
7from app.services import recommendations
8
9router = APIRouter(prefix="/experimental", tags=["experimental"])
10
11
12def require_feature(flag: str):
13 async def _guard(user: User = Depends(get_current_user)) -> None:
14 if flag in user.feature_overrides:
15 if not user.feature_overrides[flag]:
16 raise HTTPException(
17 status_code=status.HTTP_404_NOT_FOUND,
18 detail="Not found",
19 )
20 return
21 if not settings.feature_flags.get(flag, False):
22 raise HTTPException(
23 status_code=status.HTTP_404_NOT_FOUND,
24 detail="Not found",
25 )
26
27 return _guard
28
29
30@router.get(
31 "/recommendations",
32 response_model=list[RecommendationOut],
33 dependencies=[Depends(require_feature("smart_recommendations"))],
34)
35async def list_recommendations(
36 limit: int = 20,
37 user: User = Depends(get_current_user),
38) -> list[RecommendationOut]:
39 return await recommendations.for_user(user, limit=limit)
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A function that returns a dependency lets you parameterize FastAPI guards without duplicating logic per route.
- 2Returning 404 instead of 403 hides an endpoint's existence from users who aren't entitled to it.
- 3Per-user overrides checked before global defaults let you selectively enable or disable a flag for individual accounts.
Related explainers
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 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
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/gating-a-fastapi-route-behind-a-feature-flag-explained-python-a9c0/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.