.gitea | ||
app | ||
static | ||
templates | ||
.env | ||
.env_db | ||
.env_debug | ||
.gitignore | ||
docker-compose.yml | ||
Dockerfile | ||
LICENSE | ||
main.py | ||
Makefile | ||
mypy.ini | ||
pylintrc | ||
README.md | ||
requirements.txt | ||
version_code |
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
Usage
- Create a repository from this template
- For debugging, change the database connection parameters
in
.env_debug
file correspoding to the configuration of MariaDB/MySQL server on your PC- If you have no MariaDB/MySQL test server installed,
search for "mariadb install (your linux distro)",
for example: an article on DigitalOcean for Ubuntu 22.04
- If you have no MariaDB/MySQL test server installed,
search for "mariadb install (your linux distro)",
- Edit app paths, custom error pages and forms as explained in the "Structure" section
- Create your own Jinja templates in the
templates/
directory, editingbase.html
and inheriting other templates from it is recommended (seeindex,table,admin.html
for examples) - Edit or remove CSS and JS files in
static/
- Edit
sql/models,schemas,crud.py
corresponding to your database structure as explained below (Structure > Database) - Check if
Makefile
,Dockerfile
,docker-compose.yml
are correct - Run the formatter and linters (
make format
, thenmake check
) - Edit the
version_code
file if needed, build a docker image and publish it
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 |
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 correspondinglysettings
(pydantic.BaseSettings):debug
means the application is running in a development environmentsession_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
Each file in the app/forms
directory
contains a WTForms class (or multiple classes).
You can simply copy users.py
content
to create a form and use it in your project.
Also, there is one helper function in __init__.py
named get_form
for instantiating WTForms class.
It should be preferred to the direct constructor call.
Sample website
Included templates and CSS/JS files, paths, forms and SQL database are related to the sample website (for showing how the template works) and can be deleted or edited, except:
__init__.py
smain.py
common.py
respond.py
paths/errors.py
Database
- SQLAlchemy models are stored in
app/sql/models.py
- Pydantic models (schemas)
used for more handy SQLAlchemy models processing
are stored in
app/sql/schemas.py
- Functions executing SQL CRUD requests
are stored in
app/sql/crud.py
Note
As the official FastAPI documentation recommends (the link is above), there are two schemas —
User
andUserCreate
— for oneUser
SQLAlchemy model. The first one is needed for SELECT requests, and the second one is for INSERT requests (creating users). The first one contains all information about user, but the second one (UserCreate
) ommitsid
field, because we don't want to specify an ID when creating a new user, it will be generated automatically by the MariaDB server.
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, check the version_code
file and correct it if needed,
Then build a Docker image using make docker
command.
Follow this documentation page to create an account in the Docker Hub.
To publish the image, you can use make docker-push
command,
or manually enter the image name and its tag (version):
docker push yourname/yourapp:tag