fix(docs): Swagger/ReDoc-Assets lokal statt von cdn.jsdelivr.net
Security Audit / Node.js Dependency Audit (push) Canceled after 0s
Security Audit / Frontend Build (tsc + vite) (push) Canceled after 0s
Security Audit / Python Dependency Audit (push) Canceled after 0s

/docs blieb leer wenn das CDN vom Client-Netzwerk aus nicht erreichbar
war (Firewall/Proxy) – Backend lieferte korrektes HTML, aber Swagger-UI-
JS/CSS und ReDoc-JS kamen nicht an. Jetzt unter app/static/swagger-ui/
gebündelt und über eigene /docs+/redoc-Routen ausgeliefert (nur Dev,
Production weiterhin ohne interaktive Docs).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Ahyx6D3r7G1EuAc42nezn
This commit is contained in:
2026-09-02 23:11:08 +02:00
co-authored by Claude Sonnet 5
parent c1572c397d
commit 9f9dfb5be3
5 changed files with 1872 additions and 2 deletions
+29 -2
View File
@@ -3,6 +3,8 @@ from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
from fastapi.staticfiles import StaticFiles
from slowapi import _rate_limit_exceeded_handler
from slowapi.errors import RateLimitExceeded
@@ -62,14 +64,39 @@ async def lifespan(app: FastAPI):
app = FastAPI(
title=settings.app_name,
version="0.1.0",
docs_url="/docs" if not settings.is_production else None,
redoc_url="/redoc" if not settings.is_production else None,
docs_url=None, # eigene Route unten Swagger-Assets lokal statt CDN
redoc_url=None, # eigene Route unten ReDoc-Assets lokal statt CDN
lifespan=lifespan,
)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
# Swagger/ReDoc-Assets lokal ausliefern statt von cdn.jsdelivr.net Netzwerke ohne
# CDN-Zugriff (Firewall/Proxy) zeigten sonst eine leere /docs-Seite.
if not settings.is_production:
app.mount("/static", StaticFiles(directory="app/static"), name="static")
@app.get("/docs", include_in_schema=False)
async def custom_swagger_ui_html():
return get_swagger_ui_html(
openapi_url=app.openapi_url,
title=f"{app.title} - Swagger UI",
swagger_js_url="/static/swagger-ui/swagger-ui-bundle.js",
swagger_css_url="/static/swagger-ui/swagger-ui.css",
swagger_favicon_url="/static/swagger-ui/favicon.png",
)
@app.get("/redoc", include_in_schema=False)
async def custom_redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=f"{app.title} - ReDoc",
redoc_js_url="/static/swagger-ui/redoc.standalone.js",
redoc_favicon_url="/static/swagger-ui/favicon.png",
with_google_fonts=False,
)
# ── Middleware ────────────────────────────────────────────────────────────────
app.add_middleware(