tmpl-fastapi/app/respond.py

153 lines
3.7 KiB
Python

import os
import mimetypes
from functools import partial
from typing import Optional, Mapping
from fastapi import Request, Response
from fastapi.responses import RedirectResponse
from fastapi.responses import PlainTextResponse
from fastapi.responses import FileResponse
from starlette.background import BackgroundTask
from .common import templates
def with_redirect(
url: str = '/',
code: int = 302,
**kwargs) -> RedirectResponse:
"""Return a redirect to the page specified in `url`.
By default, code is 302 so method is changed to GET.
To leave the same HTTP method, use 307 status code
or call `with_redirect_307` function.
`kwargs` are passed directly
to the Response constructor
Args:
url (str, optional): Target URL, root by default
code (int, optional): HTTP response code
Returns:
FastAPI's RedirectResponse object
"""
return RedirectResponse(
url=url,
status_code=code,
**kwargs,
)
def with_text(
content: str,
code: int = 200,
**kwargs) -> PlainTextResponse:
"""Return a plain text to the user.
`kwargs` are passed directly
to the Response constructor
Args:
content (str): Plain text content
code (int, optional): HTTP response code
Returns:
FastAPI's PlainTextResponse object
"""
return PlainTextResponse(
content=content,
status_code=code,
**kwargs,
)
def with_tmpl(
name: str,
request: Request,
code: int = 200,
headers: Optional[Mapping[str, str]] = None,
background: Optional[BackgroundTask] = None,
**context) -> Response:
"""Render a Jinja2 template and return Response object.
`response_class` parameter is not needed.
A small explanation about the `request` function argument:
```python
from fastapi import Request
from . import respond
@app.get('/')
async def main_page(req: Request): # <--
return respond.with_tmpl(
'index.html',
request=req, # <--
...
)
```
FastAPI will automatically pass the Request object
to your function if you specify
the correct type hint (`: Request`)
Args:
name (str): Template filename
request (Request): FastAPI request object
code (int, optional): HTTP response code
headers (Optional[Mapping[str, str]], optional):
Additional headers, passed to the Response constructor
background (Optional[BackgroundTask], optional):
Background task, passed to the Response constructor
Returns:
FastAPI's TemplateResponse object
"""
return templates.TemplateResponse(
name=name,
context={
'request': request,
**context,
},
status_code=code,
headers=headers,
background=background,
)
def with_file(
path: os.PathLike,
mime: Optional[str] = None,
code: int = 200,
**kwargs) -> FileResponse:
"""Send the file specified in `path`
automatically guessing its mimetype if `mime` is None.
`kwargs` are passed directly
to the Response constructor
Args:
path (os.PathLike): File path
mime (Optional[str], optional): File mimetype
code (int, optional): HTTP response code
Returns:
FastAPI's FileResponse object
"""
return FileResponse(
path=path,
media_type=(
mime or
mimetypes.guess_type(path)[0]
),
status_code=code,
**kwargs,
)
# Aliases
with_template = with_tmpl
with_redirect_302 = partial(
with_redirect, code=302,
)
with_redirect_307 = partial(
with_redirect, code=307,
)