Skip to content

Commit 91c3710

Browse files
authored
Merge branch 'dev' into fix-datatable-conditional-style-types
2 parents 678bb66 + aa35e38 commit 91c3710

3 files changed

Lines changed: 59 additions & 1 deletion

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](https://semver.org/).
44

55
## [UNRELEASED]
66

7+
### Fixed
8+
- [#3805](https://github.com/plotly/dash/pull/3805) Fix FastAPI POST routes deadlock caused by middleware consuming request body. Fixes [#3801](https://github.com/plotly/dash/issues/3801).
9+
710
## [4.2.0] - 2026-06-01 - *The Freedom Update*
811

912
This release marks a major milestone for Dash, bringing unprecedented flexibility to how you build and deploy your applications.

‎dash/backends/_fastapi.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,19 @@ async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
223223
await self.app(scope, receive, send)
224224
return
225225

226-
# HTTP/WebSocket request handling
226+
# Non-Dash routes pass through to avoid consuming body stream
227+
path = scope["path"]
228+
prefix = self.dash_app.config.routes_pathname_prefix
229+
dash_prefix = prefix.rstrip("/") + "/_dash-"
230+
if (
231+
not path.startswith(dash_prefix)
232+
and path != prefix
233+
and path != prefix.rstrip("/")
234+
):
235+
await self.app(scope, receive, send)
236+
return
237+
238+
# HTTP request handling
227239
request = Request(scope, receive=receive)
228240
token = set_current_request(request)
229241

‎tests/backend_tests/test_preconfig_backends.py‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,46 @@ def test_silence_routes_logging(backend, expected_loggers):
291291
assert (
292292
logger.level == logging.ERROR
293293
), f"Logger {logger_name} should be set to ERROR level for {backend} backend"
294+
295+
296+
def test_fastapi_custom_post_route(dash_duo):
297+
"""Test that user-defined POST routes work with FastAPI backend.
298+
299+
Regression test for https://github.com/plotly/dash/issues/3801
300+
The DashMiddleware was consuming the request body for all routes,
301+
causing POST requests to user-defined routes to hang.
302+
"""
303+
from fastapi import FastAPI, Request
304+
from fastapi.responses import JSONResponse
305+
import requests
306+
307+
fastapi_app = FastAPI()
308+
309+
@fastapi_app.get("/api/echo")
310+
async def echo_get():
311+
return JSONResponse({"method": "GET", "ok": True})
312+
313+
@fastapi_app.post("/api/echo")
314+
async def echo_post(request: Request):
315+
body = await request.json()
316+
return JSONResponse({"echo": body})
317+
318+
app = Dash(__name__, server=fastapi_app)
319+
app.layout = html.Div("Dash is running")
320+
321+
dash_duo.start_server(app)
322+
323+
# Test GET request
324+
url = dash_duo.server_url
325+
resp = requests.get(f"{url}/api/echo", timeout=5)
326+
assert resp.status_code == 200
327+
assert resp.json() == {"method": "GET", "ok": True}
328+
329+
# Test POST request - this was hanging before the fix
330+
resp = requests.post(
331+
f"{url}/api/echo",
332+
json={"hello": "world"},
333+
timeout=5,
334+
)
335+
assert resp.status_code == 200
336+
assert resp.json() == {"echo": {"hello": "world"}}

0 commit comments

Comments
 (0)