fastapi-framework-mvc
A ready to use industrialized Model–View–Controller framework built on top of FastAPI — with a project generator, YAML-driven configuration, first-class SQLAlchemy multi-database support, and ready-to-go deployment targets using Gunicorn/Uvicorn (local, Docker, and Azure Functions).
Why fastapi-framework-mvc?
FastAPI is intentionally unopinionated — it gives you routers and dependency injection and lets you organize the rest yourself. That freedom is great until a project grows and every codebase invents its own layout.
fastapi-framework-mvc adds a convention-over-configuration layer so teams get a predictable, Rails/Django-style structure without giving up FastAPI's performance:
- 🏗️ A real MVC structure — controllers, models, views/templates in known places, so anyone can navigate any project.
- 🧰 A project & code generator — scaffold a new project, controllers, routers, and middlewares from the CLI instead of copy-pasting boilerplate.
- 🗄️ Configuration-driven databases — declare one or many SQLAlchemy databases in YAML, including non-builtin dialects (e.g. Informix) and read-only connections. A
@safedecorator handles session/transaction safety for you. - 🔌 Web and REST in one app — separate
controllers/web(HTML/file responses, Jinja2 templates, static assets) fromcontrollers/ws(REST APIs), each auto-registered. - 🔐 Built-in SSL — enable TLS straight from the config file.
- 🚀 Multiple deployment targets — local dev, standalone server, Gunicorn workers, Docker Compose, and Azure Functions, out of the box.
- 📦 Packageable projects — build your app into a pip package and compose several packaged apps into one server.
- ♻️ Database migrations — Allow alembic to use configured database connection(s) and drive its own migration plan over the database.
- 🤐 Secrets managment — All secrets / variables can be injected to the yaml configuration file throughout deployment environment / secret variable, names need to map the same ones into the yaml file.
Requirements
- Python 3.7+ (tested through 3.13)
pip3+
Installation
From PyPI:
pip install fastapi-framework-mvc
From source:
git clone https://github.com/frederickney/fastapi-framework-mvc.git
cd fastapi-framework-mvc
pip3 install .
Quick start
Create a new project with the CLI:
fastapi_framework_mvc.cli project -c myapp
By running this command, it will create myapp folder in the CWD as well as creating the base structure for a new project under it.
[!NOTE] By default it will create a app.py under the root folder of the project. It will be later used for developement settings and standalone single instance deployment (not recomended for full production settings).
Point the framework at your config file:
# Linux / macOS
export CONFIG_FILE=config/config.yml
# Windows (PowerShell)
$env:CONFIG_FILE = "config\config.yml"
Run it in dev mode:
# needs app.py in your app current working directory
python -m fastapi dev
For production:
- single instance:
# needs app.py in your app current working directory
python -m fastapi run
or
fastapi_framework_mvc.server -lp <listening-port>
- production-driven:
For linux:
fastapi_framework_mvc.wsgi
For windows:
fastapi_framework_mvc.asgi
[!NOTE] The CLI is also available as
python -m fastapi_framework_mvc.cli. Run any command with-hfor full usage.
Project structure
A generated project follows this layout:
myapp/
├── config/
│ └── config.yml # server, SSL, and database configuration
├── controllers/
│ ├── web/ # HTML/file controllers (registered in web.py)
│ │ └── errors/ # HTTP error handlers (404, 500, …)
│ └── ws/ # REST API controllers (registered in ws.py)
├── models/
│ ├── forms/ # request/form models
│ └── persistent/ # SQLAlchemy models
├── server/
│ ├── middleware.py # middlewares registration
│ ├── plugins.py # plugins registration
│ ├── web.py # web route registration
│ ├── ws.py # REST route registration
│ └── errorhandler.py # error route registration
├── static/ # static assets for web apps
├── template/ # Jinja2 layouts & templates
└── app.py # auto-generated app.py used for debuging or standalone execution
Configuration
All runtime configuration lives in config/config.yml.
SSL / TLS
Add an SSL block under the SERVER key:
SERVER:
SSL:
Certificate: "path to the .crt file (public key)"
PrivateKey: "path to the .pki file (private key)"
Databases
Databases are declared entirely in config — no wiring code required.
[!NOTE] This part is comming from database-connector-kit, documentation may not match, please refer to documentation from this package.
Built-in SQLAlchemy driver:
DATABASES:
default: mysql
mysql:
driver: mysql+pymysql
user: "your database user"
password: "your database user's password"
database: "your database name"
address: "your hostname"
models: "mysql" # python module placed under models.persistent
readonly: false
Non-built-in driver (Informix example):
DATABASES:
informix:
driver: informix
user: "your database user"
password: "your database user's password"
database: "your database name"
address: "your hostname"
models: "informix"
params:
SERVER: "your server name"
CLIENT_LOCALE: "your client locale"
DB_LOCALE: "your server locale"
dialects:
informix:
module: IfxAlchemy.IfxPy
class: IfxDialect_IfxPy
informix.IfxPy:
module: IfxAlchemy.IfxPy
class: IfxDialect_IfxPy
informix.pyodbc:
module: IfxAlchemy.pyodbc
class: IfxDialect_pyodbc
readonly: false
-
params— extra values sent with the connection (required ones vary by database). -
dialects— the Python modules used to translate models into SQL for non-built-in drivers. -
URL separators — default to
?(first param) and&(subsequent params). Override per database:url_param_separator: '?' params_separator: '&'
Multiple databases — just declare more database configuration entries:
DATABASES:
db01:
...
db02:
...
Defining routes
Routes are registered in three files under server/:
Error handlers (server/errorhandler.py):
server.add_exception_handler(500, controllers.web.errors.http_500)
Web (HTML/file) routes (server/web.py):
server.add_route(path='/', route=controllers.web.home.index, methods=["GET"], name='home')
# or include a FastAPI APIRouter
server.include_router(controllers.web.router, prefix='/api/v1')
REST API routes (server/ws.py):
server.add_api_route('/api/content/', controllers.ws.api.index, methods=['GET'], name='api.content')
# or include a FastAPI APIRouter
server.include_router(controllers.ws.api.v1.router, prefix='/api/v1/')
Controllers
- Web controllers live under
controllers/web. - REST controllers live under
controllers/ws.
Class-based controllers and view functions must be imported in the __init__.py of their respective module.
When a controller touches the database, decorate it with @safe from fastapi_framework_mvc.database.decorators to get safe session/transaction handling:
from fastapi_framework_mvc.database.decorators import safe
class Content(object):
@safe
@staticmethod
def index(api_param):
return api_param
class Controller(Content):
@classmethod
def index(cls, api_param: str):
return super(Controller, cls).index(api_param)
Models
Create SQLAlchemy models inside a module under models/persistent. Each model must extend the framework's base model:
from fastapi_framework_mvc.database import Database
# Use the default connection's model base…
class MyModel(Database.Model):
...
# …or bind to a named connection:
# Database.get_models_by_name('your_connection_name')
Import your models in your module's __init__.py, then import that module in the __init__.py of models.persistent.
Views: static & templates
static/— CSS, JS, images, and other static assets for web apps.template/— Jinja2 layouts and templates. Templates support layout inheritance, so pages only need to define their editable content.
CLI reference
Run any command with -h for full options. All commands work via the fastapi_framework_mvc.cli executable or python -m fastapi_framework_mvc.cli.
| Task | Command |
|---|---|
| Create a project | fastapi_framework_mvc.cli project -c <name> |
| Create a standalone controller | fastapi_framework_mvc.cli controller -c controllers/ws/contents |
| Create a router controller | fastapi_framework_mvc.cli controller -c controllers/ws/contents -router |
| Install a standalone controller | fastapi_framework_mvc.cli manager -l controllers/ws/contents |
| Install a router controller (with prefix) | fastapi_framework_mvc.cli manager -l controllers/ws/contents -p /api/ |
| Create a middleware | fastapi_framework_mvc.cli middleware -c grant/authorization |
Running & deployment
Local (FastAPI CLI)
export CONFIG_FILE=config/config.yml # set once per shell
python -m fastapi dev # development
python -m fastapi run # production
Standalone server
python -m fastapi_framework_mvc.server
Gunicorn with worker processes
python -m fastapi_framework_mvc.wsgi
Docker Compose
docker-compose up # first run (build + start)
docker-compose start # start
docker-compose restart # restart
docker-compose stop # stop
Azure Functions
# function_app.py
import azure.functions as functions
import fastapi_framework_mvc.azure
import os
os.environ.setdefault('CONFIG_FILE', './config/config.yml')
app = functions.AsgiFunctionApp(
fastapi_framework_mvc.azure.AzureFunctionsApp(),
http_auth_level=functions.AuthLevel.ANONYMOUS,
)
Ensure your host.json disables the route prefix:
{
"extensions": {
"http": { "routePrefix": "" }
}
}
Packaging projects
A project can be built into a pip package and reused by the framework. Add a pyproject.toml (recommended: in the parent directory of your project) that builds your project into a package.
You'll still provide a server module (and a models.persistent module if you use databases). In server/__init__.py, re-export the submodules from your package:
# server/__init__.py
from your_project.server import web, ws, errorhandler, plugins, middleware, socket
To compose multiple packaged apps into one server, recreate the server module tree and delegate to each app's routes instead of rewriting them:
# server/ws.py — combining two projects
import your_first_project.server.ws
import your_second_project.server.ws
class Route(object):
"""Configure all REST (ws) routes for the server."""
def __init__(self, server):
"""
:param server: FastAPI instance
:type server: fastapi.FastAPI
"""
your_first_project.server.ws.Route(server)
your_second_project.server.ws.Route(server)
For models, re-export from each package in models/persistent/__init__.py:
# single project
from your_project.models.persistent import *
# multiple projects with potential model-name conflicts
from your_first_project.models import persistent as your_first_project
from your_second_project.models import persistent as your_second_project
Contributing
Contributions are welcome! To get involved:
- Open an issue to discuss a bug or feature.
- Fork the repository and create a feature branch.
- Make your change, add or update examples where relevant, and open a pull request.
Working examples live in the examples/ directory (a base app and an openid app) — they're a good starting point for both using and contributing to the framework.
License
Distributed under the GNU General Public License v3.0. See LICENSE for details.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapi_framework_mvc-1.3.2.tar.gz.
File metadata
- Download URL: fastapi_framework_mvc-1.3.2.tar.gz
- Upload date:
- Size: 116.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
997ab6a8e43bbc93b0cf67dc2e17bb5c9fb6a78a762883da7d67cc37ce3d47be
|
|
| MD5 |
31dfe8f9b7d0950d4912765c568172c1
|
|
| BLAKE2b-256 |
be57b26afcd4aba6429bb2a52e61255aefa6a69b3d8b2aaf5bb5b3660018e4e8
|
File details
Details for the file fastapi_framework_mvc-1.3.2-py3-none-any.whl.
File metadata
- Download URL: fastapi_framework_mvc-1.3.2-py3-none-any.whl
- Upload date:
- Size: 116.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a77bcc9dce10bb277a74ea2257f8033242110e3ab667d34b55c0f8b605127277
|
|
| MD5 |
d3f0a6b389cfc52955a15366f5b87c7c
|
|
| BLAKE2b-256 |
c0b8a0949cf6a54819200a213c5252a34f03ca2511de664ad1300e86a8295db7
|