tmpl-fastapi/app/respond.py

154 lines
3.7 KiB
Python
Raw Normal View History

import os
import mimetypes
from functools import partial
from typing import Optional, Mapping
from fastapi import Request, Response
2023-02-20 12:09:43 +04:00
from fastapi.responses import RedirectResponse
from fastapi.responses import PlainTextResponse
from fastapi.responses import FileResponse
2023-02-20 12:09:43 +04:00
from starlette.background import BackgroundTask
from .common import templates
2023-02-20 12:09:43 +04:00
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
2023-02-20 12:09:43 +04:00
Args:
url (str, optional): Target URL, root by default
2023-02-20 12:09:43 +04:00
code (int, optional): HTTP response code
Returns:
FastAPI's RedirectResponse object
"""
return RedirectResponse(
url=url,
status_code=code,
**kwargs,
2023-02-20 12:09:43 +04:00
)
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
2023-02-20 12:09:43 +04:00
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,
2023-02-20 12:09:43 +04:00
)
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=(
2023-02-27 19:05:57 +04:00
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,
)