.gitea | ||
app | ||
static | ||
templates | ||
.env | ||
.env_db | ||
.env_debug | ||
.gitignore | ||
docker-compose.yml | ||
Dockerfile | ||
LICENSE | ||
main.py | ||
Makefile | ||
pylintrc | ||
README.md | ||
requirements.txt |
FastAPI template
It is a simple and handy FastAPI template
for combined frontend and backend as in Flask.
Includes Jinja, WTForms, MySQL ORM and Docker.
Features
- Basic FastAPI app
@app.route
s are defined in separate files- Lots of helper functions
- Jinja2 templates, WTForms
- MySQL/MariaDB database, SQLAlchemy 2
- AutoPEP8 formatter, MyPy and Pylint
- Dockerfile, Docker-Compose
Structure
Configuration
.env
s
.env_debug
contains the DB configuration and tokens for the development environment, must not be used in production.env
is a config for the application itself, loaded only in docker-compose by default.env_db
is a config for MySQL/MariaDB server, also loaded only in docker-compose for the mariadb container
The main config loaded by app/common.py
:
templates_dir
,static_dir
contain the paths to templates and static files directories correspondinglydebug_env
is a path to.env_debug
is_debug
is True when DEBUG env variable is set, and then.env_debug
is loaded automaticallysettings
(pydantic.BaseSettings):session_key
,csrf_key
are secret keys for WTForms CSRF protection;
generated with secrets.token_urlsafe if are not set in the environment variables
templates
is a Jinja2Templates FastAPI object, shouldn't be used manually, see Helper Functions -> respond.with_tmpl below
The database config loaded by sql/db.py
:
sql_settings
(pydantic.BaseSettings):db_host
db_port
db_user
db_password
db_database
db_url
is the MySQL connection URL generated from the sql_settings configuration;
just edit the line declaringdb_url
indb.py
if you are going to use other DBMS, e.g. PostgreSQL
Paths
app/paths
directory contains all FastAPI paths
separated into multiple files.
Each file have a class inside with the add_paths
method.
This method is called on application startup.
You can
- add your own paths to the existing files
- rename or delete a file in
app/paths/
(it's not recommended to do this witherrors.py
, see about error pages below) - create a new file in this directory
copying the contents of
pages.py
Note
In the paths files FastAPI's decorators are called with
@self.app.
, not just@app.
In case of deleteing/renaming/creating any paths files,
app/main.py
also must be modified:
- Find the comment
# Add your own paths...
- Add or remove import statements below
- Add or remove elements in
paths
list below
Custom Error Pages
app/paths/errors.py
automatically adds error handlers
when the application launches.
By default, 404 and 500 HTTP codes are configured
for the custom pages (templates/404.html
and 500.html
),
but you can add your own:
- Open
errors.py
- Find the comment
# Add other...
- Add (or remove) elements to the list below
WTForms
TODO
Database
TODO
Usage
Makefile
Make commands:
Command | Description |
---|---|
make format |
Format the code using AutoPEP8 |
make check |
Check the code with linters (MyPy, Pylint) |
make dev |
Run the app in development mode |
make prod |
Run a production server |
make docker |
Build a docker image from Dockerfile |
make clean |
Clean all cache |
Helper functions
respond.py
Import: from . import respond
with_redirect(url=/, code=200, ...)
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.
args
and kwargs
are passed directly
to the Response contructor.
Args: url (str, optional): Target URL, root by default code (int, optional): HTTP response code
Returns: FastAPI's RedirectResponse object
with_redirect_302(url=/, ...)
with_redirect_307(url=/, ...)
As said before,
- HTTP 302 Found redirects to a page without saving the same method as in the current request
- HTTP 307 Temporary Redirect doesn't change the method (POST request = POST method after redirect)
with_text(content, code=200, ...)
Return a plain text to the user.
args
and kwargs
are passed directly
to the Response contructor.
Args: content (str): Plain text content code (int, optional): HTTP response code
Returns: FastAPI's PlainTextResponse object
with_template(name, request, code=200, ..., **context)
with_tmpl(name, request, code=200, ..., **context)
Render a Jinja2 template and return Response object.
response_class
parameter is not needed.
A small explanation about the request
function argument:
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
with_file(path, mime=None, code=200, ...)
Send the file specified in path
automatically guessing its mimetype if mime
is None.
args
and kwargs
are passed directly
to the Response contructor.
Args: path (os.PathLike): File path mime (Optional[str], optional): File mimetype code (int, optional): HTTP response code
Returns: FileResponse: FastAPI's FileResponse object
forms/__init__.py
Import: from . import forms
async get_form(form, req)
Almost the same as form.from_formdata
,
and must be used instead of instantiating
form object directly as in Flask.
See respond.with_tmpl
for explanation
about the request
argument.
Args: form (Type[StarletteForm]): StarletteForm class req (Request): Request object
Returns: StarletteForm instance
sql/db.py
async get_db()
FastAPI dependency returning database Session object.
Code is copied from the official docs.
Yields: SQLAlchemy Session object
Publishing app
First of all, build an image: make docker
Follow this documentation page
to upload your image to Docker Hub.