Skip to content

Commit 53ceed7

Browse files
committed
fix: add Dash and Shiny framework integration examples to documentation
1 parent bf974f1 commit 53ceed7

1 file changed

Lines changed: 117 additions & 19 deletions

File tree

docs/frameworks.md

Lines changed: 117 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
### Note: Overriding the `Server` Header in Uvicorn-based Frameworks
2929

30-
If you're using Uvicorn as the ASGI server (commonly used with frameworks like FastAPI, Starlette, and others), Uvicorn automatically injects a `Server: uvicorn` header into all HTTP responses by default. This can lead to multiple `Server` headers when using `Secure.py` to set a custom `Server` header.
30+
If you're using Uvicorn as the ASGI server (commonly used with frameworks like FastAPI, Starlette, and others), Uvicorn automatically injects a `Server: uvicorn` header into all HTTP responses by default. This can lead to multiple `Server` headers when using `secure` to set a custom `Server` header.
3131

3232
To prevent Uvicorn from adding its default `Server` header, you can disable it by passing the `--no-server-header` option when running Uvicorn, or by setting `server_header=False` in the `uvicorn.run()` method:
3333

@@ -149,14 +149,7 @@ class HelloWorld:
149149
cherrypy.response.headers.update(secure_headers.headers)
150150
return b"Hello, world"
151151

152-
config = {
153-
"/": {
154-
"tools.response_headers.on": True,
155-
"tools.response_headers.headers": secure_headers.headers
156-
}
157-
}
158-
159-
cherrypy.quickstart(HelloWorld(), "/", config)
152+
cherrypy.quickstart(HelloWorld())
160153
```
161154

162155
### Single Route Example
@@ -178,6 +171,51 @@ cherrypy.quickstart(HelloWorld())
178171

179172
---
180173

174+
## Dash
175+
176+
**[Dash](https://dash.plotly.com/)** is a Python framework for building interactive data apps and dashboards, built on top of Plotly.js, React, and Flask.
177+
178+
### Middleware Example
179+
180+
```python
181+
import dash
182+
from dash import html
183+
from secure import Secure
184+
185+
secure_headers = Secure.with_default_headers()
186+
187+
app = dash.Dash(__name__)
188+
server = app.server
189+
190+
app.layout = html.Div("Hello Dash!")
191+
192+
193+
@server.after_request
194+
def add_security_headers(response):
195+
secure_headers.set_headers(response)
196+
return response
197+
```
198+
199+
#### Alternative: WSGI middleware
200+
201+
```python
202+
import dash
203+
from dash import html
204+
from secure import Secure
205+
from secure.middleware.wsgi import SecureWSGIMiddleware
206+
207+
secure_headers = Secure.with_default_headers()
208+
209+
app = dash.Dash(__name__)
210+
server = app.server # Flask app underneath Dash
211+
212+
app.layout = html.Div("Hello Dash!")
213+
214+
server.wsgi_app = SecureWSGIMiddleware(server.wsgi_app, secure=secure_headers)
215+
```
216+
217+
---
218+
181219
## Django
182220

183221
**[Django](https://www.djangoproject.com)** is a high-level Python web framework that encourages rapid development and clean, pragmatic design.
@@ -262,7 +300,19 @@ app.add_route("/", HelloWorldResource())
262300

263301
**[FastAPI](https://fastapi.tiangolo.com)** is a modern, fast web framework for building APIs with Python 3.6+.
264302

265-
### Middleware Example
303+
#### Recommended: `SecureASGIMiddleware`
304+
305+
```python
306+
from fastapi import FastAPI
307+
from secure import Secure
308+
from secure.middleware import SecureASGIMiddleware
309+
310+
app = FastAPI()
311+
secure_headers = Secure.with_default_headers()
312+
app.add_middleware(SecureASGIMiddleware, secure=secure_headers)
313+
```
314+
315+
#### Alternative: route-level hook with `@app.middleware("http")`
266316

267317
```python
268318
from fastapi import FastAPI
@@ -314,6 +364,19 @@ def add_security_headers(response: Response):
314364
return response
315365
```
316366

367+
#### Alternative: WSGI middleware
368+
369+
```python
370+
from flask import Flask
371+
from secure import Secure
372+
from secure.middleware import SecureWSGIMiddleware
373+
374+
app = Flask(__name__)
375+
secure_headers = Secure.with_default_headers()
376+
377+
app.wsgi_app = SecureWSGIMiddleware(app.wsgi_app, secure=secure_headers)
378+
```
379+
317380
### Single Route Example
318381

319382
```python
@@ -529,6 +592,7 @@ secure_headers = Secure.with_default_headers()
529592
@app.middleware("response")
530593
async def add_security_headers(request, resp):
531594
secure_headers.set_headers(resp)
595+
return resp
532596
```
533597

534598
### Single Route Example
@@ -549,40 +613,74 @@ async def index(request):
549613

550614
---
551615

616+
## Shiny
617+
618+
**[Shiny](https://shiny.posit.co/py/)** is a fully reactive framework for building rich, interactive web apps in pure Python—without needing to learn JavaScript or front-end frameworks.
619+
620+
### Middleware Example
621+
622+
```python
623+
from secure import Secure
624+
from secure.middleware import SecureASGIMiddleware
625+
from shiny import App, ui
626+
627+
secure_headers = Secure.with_default_headers()
628+
629+
app_ui = ui.page_fluid("Hello Shiny!")
630+
631+
632+
def server(input, output, session):
633+
pass
634+
635+
636+
app = App(app_ui, server)
637+
638+
app = SecureASGIMiddleware(app, secure=secure_headers)
639+
```
640+
641+
---
642+
552643
## Starlette
553644

554645
**[Starlette](https://www.starlette.io)** is a lightweight ASGI framework.
555646

556647
### Middleware Example
557648

558649
```python
559-
from starlette.applications import Starlette
560-
from starlette.responses import Response
561-
from starlette.middleware.base import BaseHTTPMiddleware
562650
from secure import Secure
651+
from secure.middleware import SecureASGIMiddleware
652+
from starlette.applications import Starlette
653+
from starlette.responses import JSONResponse
563654

564655
secure_headers = Secure.with_default_headers()
565656

566-
class SecurityHeadersMiddleware(BaseHTTPMiddleware):
567-
async def dispatch(self, request, call_next):
568-
response = await call_next(request)
569-
await secure_headers.set_headers_async(response)
570-
return response
657+
app = Starlette()
658+
app.add_middleware(SecureASGIMiddleware, secure=secure_headers)
659+
660+
661+
@app.route("/")
662+
async def read_root(request):
663+
return JSONResponse({"hello": "world"})
571664
```
572665

573666
### Single Route Example
574667

575668
```python
669+
from secure import Secure
576670
from starlette.applications import Starlette
577671
from starlette.responses import Response
578-
from secure import Secure
672+
from starlette.routing import Route
579673

580674
secure_headers = Secure.with_default_headers()
581675

676+
582677
async def homepage(request):
583678
response = Response("Hello, world")
584679
await secure_headers.set_headers_async(response)
585680
return response
681+
682+
683+
app = Starlette(routes=[Route("/", homepage)])
586684
```
587685

588686
---

0 commit comments

Comments
 (0)