diff --git a/docs/en/docs/advanced/response-directly.md b/docs/en/docs/advanced/response-directly.md index c9d18649fa..fa7877b498 100644 --- a/docs/en/docs/advanced/response-directly.md +++ b/docs/en/docs/advanced/response-directly.md @@ -74,6 +74,20 @@ When using a `response_model` or return type, FastAPI won't use the `jsonable_en Instead it takes the JSON bytes generated with Pydantic using the response model (or return type) and returns a `Response` with the right media type for JSON directly (`application/json`). +## Background Tasks and Custom Responses { #background-tasks-and-custom-responses } + +/// warning + +If you return a `Response` with a `background` parameter **and** also use the `BackgroundTasks` dependency injection, the injected background tasks will be **silently ignored**. + +FastAPI only assigns injected background tasks to the response when `response.background is None`. If your `Response` already has a background task attached, the injected tasks are dropped without any error or warning. + +Use one mechanism or the other, not both in the same endpoint: + +{* ../../docs_src/response_directly/tutorial003.py hl[18,25] *} + +/// + ## Notes { #notes } When you return a `Response` directly its data is not validated, converted (serialized), or documented automatically. diff --git a/docs_src/response_directly/tutorial003.py b/docs_src/response_directly/tutorial003.py new file mode 100644 index 0000000000..19e8aaa9aa --- /dev/null +++ b/docs_src/response_directly/tutorial003.py @@ -0,0 +1,26 @@ +from fastapi import BackgroundTasks, FastAPI +from starlette.responses import JSONResponse + +app = FastAPI() + + +def write_log(message: str): + with open("log.txt", mode="a") as log: + log.write(message) + + +# Correct: use only BackgroundTasks (no background= on Response) +@app.get("/correct") +async def send_notification(background_tasks: BackgroundTasks): + background_tasks.add_task(write_log, "Notification sent") + return JSONResponse(content={"message": "done"}) + + +# Wrong: background= on Response silently overrides BackgroundTasks +@app.get("/wrong") +async def send_notification_wrong(background_tasks: BackgroundTasks): + background_tasks.add_task(write_log, "This task will NOT run") + return JSONResponse( + content={"message": "done"}, + background=None, # If this were a BackgroundTask, it would override the line above + )