Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default.
+You can return a `RedirectResponse` directly:
+
```Python hl_lines="2 9"
{!../../../docs_src/custom_response/tutorial006.py!}
```
+---
+
+Or you can use it in the `response_class` parameter:
+
+
+```Python hl_lines="2 7 9"
+{!../../../docs_src/custom_response/tutorial006b.py!}
+```
+
+If you do that, then you can return the URL directly from your *path operation* function.
+
+In this case, the `status_code` used will be the default one for the `RedirectResponse`, which is `307`.
+
+---
+
+You can also use the `status_code` parameter combined with the `response_class` parameter:
+
+```Python hl_lines="2 7 9"
+{!../../../docs_src/custom_response/tutorial006c.py!}
+```
+
### `StreamingResponse`
Takes an async generator or a normal generator/iterator and streams the response body.
{!../../../docs_src/custom_response/tutorial009.py!}
```
+You can also use the `response_class` parameter:
+
+```Python hl_lines="2 8 10"
+{!../../../docs_src/custom_response/tutorial009b.py!}
+```
+
+In this case, you can return the file path directly from your *path operation* function.
+
## Default response class
When creating a **FastAPI** class instance or an `APIRouter` you can specify which response class to use by default.
@app.get("/typer")
-async def read_typer():
+async def redirect_typer():
return RedirectResponse("https://typer.tiangolo.com")
--- /dev/null
+from fastapi import FastAPI
+from fastapi.responses import RedirectResponse
+
+app = FastAPI()
+
+
+@app.get("/fastapi", response_class=RedirectResponse)
+async def redirect_fastapi():
+ return "https://fastapi.tiangolo.com"
--- /dev/null
+from fastapi import FastAPI
+from fastapi.responses import RedirectResponse
+
+app = FastAPI()
+
+
+@app.get("/pydantic", response_class=RedirectResponse, status_code=302)
+async def redirect_pydantic():
+ return "https://pydantic-docs.helpmanual.io/"
--- /dev/null
+from fastapi import FastAPI
+from fastapi.responses import FileResponse
+
+some_file_path = "large-video-file.mp4"
+app = FastAPI()
+
+
+@app.get("/", response_class=FileResponse)
+async def main():
+ return some_file_path
endpoint: Callable[..., Coroutine[Any, Any, Response]],
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[Depends]] = None,
summary: Optional[str] = None,
import http.client
+import inspect
from enum import Enum
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast
)
callbacks[callback.name] = {callback.path: cb_path}
operation["callbacks"] = callbacks
- status_code = str(route.status_code)
+ if route.status_code is not None:
+ status_code = str(route.status_code)
+ else:
+ # It would probably make more sense for all response classes to have an
+ # explicit default status_code, and to extract it from them, instead of
+ # doing this inspection tricks, that would probably be in the future
+ # TODO: probably make status_code a default class attribute for all
+ # responses in Starlette
+ response_signature = inspect.signature(current_response_class.__init__)
+ status_code_param = response_signature.parameters.get("status_code")
+ if status_code_param is not None:
+ if isinstance(status_code_param.default, int):
+ status_code = str(status_code_param.default)
operation.setdefault("responses", {}).setdefault(status_code, {})[
"description"
] = route.response_description
def get_request_handler(
dependant: Dependant,
body_field: Optional[ModelField] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
response_class: Union[Type[Response], DefaultPlaceholder] = Default(JSONResponse),
response_field: Optional[ModelField] = None,
response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
exclude_none=response_model_exclude_none,
is_coroutine=is_coroutine,
)
- response = actual_response_class(
- content=response_data,
- status_code=status_code,
- background=background_tasks, # type: ignore # in Starlette
- )
+ response_args: Dict[str, Any] = {"background": background_tasks}
+ # If status_code was set, use it, otherwise use the default from the
+ # response class, in the case of redirect it's 307
+ if status_code is not None:
+ response_args["status_code"] = status_code
+ response = actual_response_class(response_data, **response_args)
response.headers.raw.extend(sub_response.headers.raw)
if sub_response.status_code:
response.status_code = sub_response.status_code
endpoint: Callable[..., Any],
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
endpoint: Callable[..., Any],
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
path: str,
*,
response_model: Optional[Type[Any]] = None,
- status_code: int = 200,
+ status_code: Optional[int] = None,
tags: Optional[List[str]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
summary: Optional[str] = None,
client = TestClient(app)
+openapi_schema = {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/typer": {
+ "get": {
+ "summary": "Redirect Typer",
+ "operationId": "redirect_typer_typer_get",
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ }
+ },
+ }
+ }
+ },
+}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == openapi_schema
+
+
def test_get():
response = client.get("/typer", allow_redirects=False)
assert response.status_code == 307, response.text
--- /dev/null
+from fastapi.testclient import TestClient
+
+from docs_src.custom_response.tutorial006b import app
+
+client = TestClient(app)
+
+
+openapi_schema = {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/fastapi": {
+ "get": {
+ "summary": "Redirect Fastapi",
+ "operationId": "redirect_fastapi_fastapi_get",
+ "responses": {"307": {"description": "Successful Response"}},
+ }
+ }
+ },
+}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == openapi_schema
+
+
+def test_redirect_response_class():
+ response = client.get("/fastapi", allow_redirects=False)
+ assert response.status_code == 307
+ assert response.headers["location"] == "https://fastapi.tiangolo.com"
--- /dev/null
+from fastapi.testclient import TestClient
+
+from docs_src.custom_response.tutorial006c import app
+
+client = TestClient(app)
+
+
+openapi_schema = {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/pydantic": {
+ "get": {
+ "summary": "Redirect Pydantic",
+ "operationId": "redirect_pydantic_pydantic_get",
+ "responses": {"302": {"description": "Successful Response"}},
+ }
+ }
+ },
+}
+
+
+def test_openapi_schema():
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == openapi_schema
+
+
+def test_redirect_status_code():
+ response = client.get("/pydantic", allow_redirects=False)
+ assert response.status_code == 302
+ assert response.headers["location"] == "https://pydantic-docs.helpmanual.io/"
--- /dev/null
+from pathlib import Path
+
+from fastapi.testclient import TestClient
+
+from docs_src.custom_response import tutorial009
+from docs_src.custom_response.tutorial009 import app
+
+client = TestClient(app)
+
+
+def test_get(tmp_path: Path):
+ file_path: Path = tmp_path / "large-video-file.mp4"
+ tutorial009.some_file_path = str(file_path)
+ test_content = b"Fake video bytes"
+ file_path.write_bytes(test_content)
+ response = client.get("/")
+ assert response.content == test_content
--- /dev/null
+from pathlib import Path
+
+from fastapi.testclient import TestClient
+
+from docs_src.custom_response import tutorial009b
+from docs_src.custom_response.tutorial009b import app
+
+client = TestClient(app)
+
+
+def test_get(tmp_path: Path):
+ file_path: Path = tmp_path / "large-video-file.mp4"
+ tutorial009b.some_file_path = str(file_path)
+ test_content = b"Fake video bytes"
+ file_path.write_bytes(test_content)
+ response = client.get("/")
+ assert response.content == test_content