-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbasic.py
More file actions
106 lines (79 loc) · 2.93 KB
/
basic.py
File metadata and controls
106 lines (79 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
"""FastAPI — Basic Usage Example.
Demonstrates the core api-shield decorators on both ShieldRouter and a plain
FastAPI APIRouter.
Run:
uv run uvicorn examples.fastapi.basic:app --reload
Then visit:
http://localhost:8000/docs — filtered Swagger UI
http://localhost:8000/redoc — filtered ReDoc
Expected behaviour (production env):
GET /health → 200 always (@force_active)
GET /payments → 503 MAINTENANCE_MODE (@maintenance)
GET /debug → 404 silent (@env_only("dev"))
GET /old-endpoint → 503 ROUTE_DISABLED (@disabled)
GET /v1/users → 200 + deprecation headers (@deprecated)
Switch to dev to unlock /debug:
APP_ENV=dev uv run uvicorn examples.fastapi.basic:app --reload
"""
import os
from fastapi import FastAPI
from shield.core.config import make_engine
from shield.fastapi import (
ShieldMiddleware,
ShieldRouter,
apply_shield_to_openapi,
deprecated,
disabled,
env_only,
force_active,
maintenance,
)
CURRENT_ENV = os.getenv("APP_ENV", "production")
engine = make_engine(current_env=CURRENT_ENV)
router = ShieldRouter(engine=engine)
# ---------------------------------------------------------------------------
# Routes with shield decorators
# ---------------------------------------------------------------------------
@router.get("/health")
@force_active
async def health():
"""Always 200 — bypasses every shield check."""
return {"status": "ok", "env": CURRENT_ENV}
@router.get("/payments")
@maintenance(reason="Scheduled database migration — back at 04:00 UTC")
async def get_payments():
"""Returns 503 MAINTENANCE_MODE."""
return {"payments": []}
@router.get("/debug")
@env_only("dev")
async def debug():
"""Returns silent 404 in production. Set APP_ENV=dev to unlock."""
return {"debug": True, "env": CURRENT_ENV}
@router.get("/old-endpoint")
@disabled(reason="Use /v2/endpoint instead")
async def old_endpoint():
"""Returns 503 ROUTE_DISABLED."""
return {}
@router.get("/v1/users")
@deprecated(sunset="Sat, 01 Jan 2027 00:00:00 GMT", use_instead="/v2/users")
async def v1_users():
"""Returns 200 with Deprecation, Sunset, and Link response headers."""
return {"users": [{"id": 1, "name": "Alice"}]}
@router.get("/v2/users")
async def v2_users():
"""Active successor to /v1/users."""
return {"users": [{"id": 1, "name": "Alice"}]}
# ---------------------------------------------------------------------------
# App assembly
# ---------------------------------------------------------------------------
app = FastAPI(
title="api-shield — Basic Example",
description=(
"Core decorators: `@maintenance`, `@disabled`, `@env_only`, "
"`@force_active`, `@deprecated`.\n\n"
f"Current environment: **{CURRENT_ENV}**"
),
)
app.add_middleware(ShieldMiddleware, engine=engine)
app.include_router(router)
apply_shield_to_openapi(app, engine)