A thin convention-and-scaffolding layer over FastAPI + SQLAlchemy — collapses the model/repository/service/schema/router module shape into one declaration.
Project description
🥭 mango
FastAPI + SQLAlchemy, without the boilerplate.
mango.Router is fastapi.APIRouter. mango.Schema is pydantic.BaseModel.
mango doesn't reimplement your stack — it gives it one front door, then
removes everything you'd otherwise hand-write around it: module wiring,
CRUD repositories, DB setup, auth guards, error mapping, pagination,
background jobs, migrations, and security middleware.
Quickstart · Why mango · Full guide · Project structure · Contributing
The pitch, in code
Without mango — a plain-CRUD module is a router, a repository, a schema file, engine/session setup, and manual error handling:
# ~80+ lines across models.py / repository.py / schemas.py / router.py / main.py
With mango — the same module, in full:
import uuid
from mango import Router, Schema, MangoRepository, build_crud_router, Database
class Thing(Base):
__tablename__ = "things"
id: Mapped[uuid.UUID] = mapped_column(primary_key=True)
name: Mapped[str]
class ThingRepository(MangoRepository[Thing]):
model = Thing
class ThingRead(Schema):
id: uuid.UUID
name: str
router = build_crud_router(
repository=ThingRepository, read_schema=ThingRead,
get_db=db.get_db, id_type=uuid.UUID, prefix="/things",
)
That's a full GET /things/, GET /things/{id}, DELETE /things/{id}
REST endpoint set — 404s, pagination, error handling, all included. No
import fastapi. No import pydantic. No hand-wired main.py.
🚀 Quickstart
pip install mangoframe
mango init demo_shop
cd demo_shop
mango new-module items
mango new-module auto-detects the project via project.mango (written
by mango init) and wires the new module into app/registry.py for you
— run it from anywhere inside the project, no directory argument needed.
Already made and cd'd into an empty folder (maybe one git init ran
in already)? mango init . scaffolds it in place instead of nesting a
redundant subdirectory — the project name is taken from the folder.
# app/main.py — generated for you, shown here for reference
import mango
from app import registry # imports every module for its registration side effect
app = mango.App(title="demo_shop")
app.mount_all()
DATABASE_URL=postgresql+asyncpg://user:pass@localhost/demo_shop uvicorn app.main:app --reload
pip install name is mangoframe (mango and mango-framework
were already taken on PyPI) — the import name is always mango.
🥭 Why mango
FastAPI and SQLAlchemy are both excellent at what they do. What they
don't give you is a convention — every team ends up hand-rolling the
same models.py/repository.py/service.py/schemas.py/router.py/
__init__.py shape, the same main.py router-mounting list, the same
generic CRUD repository, the same try/except HTTPException translation
at every error site. mango is that convention, packaged:
| You'd hand-write | mango gives you |
|---|---|
__init__.py re-exports per module |
@mango.module — derived, not maintained |
main.py router-mounting list |
app.mount_all() |
| A generic repository base class | MangoRepository — get/add/update/delete/list/count/search, plus get_or_404, batch ops, eager-loading |
create_async_engine + get_db() boilerplate |
mango.Database(url) |
Domain-error → HTTP status try/except |
raise mango.NotFoundError(...) |
| A full CRUD router | mango.build_crud_router(...) — optionally paginated |
| verify-token → load-user → check-role chain | mango.Auth — pluggable, not opinionated about your token provider |
| Security headers / rate limiting | On by default in mango.App, or one kwarg |
alembic.ini + async env.py |
mango init-migrations app.db:Base |
| A new project's folder skeleton | mango init <name> |
A module with real, non-generic business logic still writes that logic by hand — mango only removes the boilerplate around it. See the size table below for the receipts.
No magic, no lock-in. mango.Router/mango.Schema/etc. are the
literal FastAPI/Pydantic classes — anything written for FastAPI
directly (a raw APIRouter, a third-party plugin, an app you're
migrating incrementally) works alongside mango without conversion.
What's inside
App— owns its FastAPI instance, ASGI-callable, wires in security headers by default and opt-in CORS/rate-limiting, exposes aPluginextension point andon_startup/on_shutdownhooks.MangoModule+@mango.module— declare a module as one class; mango derives its public API instead of a hand-written__init__.py.MangoRepository— generic async CRUD,get_or_404,exists,add_many/delete_many,filter_by(**equals), eager-loading viaoptions=, andlist_page/search_pagefor pagination.Auth— pluggable token verification + user loading +require_role/require/current_userFastAPI dependencies.MangoError+ subclasses +register_error_handlers— domain exceptions that map straight to clean HTTP responses, plus a catch-all so an unhandled bug returns a generic 500, never a leaked traceback.build_crud_router— a full list/get/create/update/delete router from a repository + schemas, one call.run_in_background/Database.spawn— fire-and-forget work with its own session and a logged (not swallowed) exception on failure.init_migrations/init_project— scaffold Alembic and a whole new project's folder structure, via themangoCLI.mango modules/mango routes— list registered modules (mount order,depends_on) or every mounted HTTP route, without booting the server and clicking through/docs.mango remove-module— deletes a module's directory and un-wires itsregistry.pyimport; the inverse ofnew-module.mango doctor— sanity-checks an existing project: modules created by hand but never wired intoregistry.py(or the reverse — a stale import pointing at a deleted module), a missing.env, apyproject.tomlthat lost itsmangoframedependency.mango migrate "<message>"— wraps the two-command Alembic loop (revision --autogenerate+upgrade head) every model change needs.
Full tour with examples: docs/GUIDE.md. Folder-structure convention and the reasoning behind it: docs/PROJECT_STRUCTURE.md.
📏 What it actually cuts
Every piece exists to measurably shorten a project's code — not to add abstraction for its own sake. Per module, roughly:
| What you'd hand-write | Lines | With mango |
|---|---|---|
__init__.py re-exports |
15–30 | 0 |
main.py router mounting |
1–2/module | 0 |
| Generic repository CRUD | 30–50 | 0 |
DB engine/session/get_db() |
~15 | 3 |
| Plain-CRUD router | 60–90 | ~10 |
| Domain-error → HTTP mapping | 5–10/site | 0 |
| Auth guard | 20–40 | ~10 |
| Background task + own session | 10–15 | 1 |
Alembic env.py |
~100 | 0 |
| Security headers middleware | ~15 | 0 |
| New project skeleton | ~80 | 0 |
Development
git clone https://github.com/rhydham-mittal27/mango.git
cd mango
pip install -e ".[dev]"
pytest -q
See CONTRIBUTING.md for the ground rules (every change ships with a test and a changelog entry, no exceptions).
Status
Module registry, generic repository, pagination, mount ordering, DB
setup, background tasks, auth guards, error mapping, generated CRUD
routers, Alembic + project scaffolding, production hardening, a plugin
system, and a full FastAPI/Pydantic re-export surface are all in place
— a project can be built end to end importing only mango. CI runs the
full suite across Python 3.11/3.12/3.13 on every push.
Honestly: this is a young project. No production mileage beyond one real integration, a small test suite, a single maintainer. If you use it and something breaks, that's expected — open an issue or a PR. See CONTRIBUTING.md.
License
MIT — use it for anything, including in production, at your own judgment given the "Status" section above.
Project 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 mangoframe-0.6.0.tar.gz.
File metadata
- Download URL: mangoframe-0.6.0.tar.gz
- Upload date:
- Size: 84.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e96bfd5b5fc548003b717ad7af194ff9331ae567afa0e350fa7070534b8dbc1
|
|
| MD5 |
985d6cdaa148a0d71e82902756ef8afc
|
|
| BLAKE2b-256 |
a2b6a225aec7ad2e9fd1a5bc07930ffb2348b98810a3620b8da5efc71898b7cc
|
File details
Details for the file mangoframe-0.6.0-py3-none-any.whl.
File metadata
- Download URL: mangoframe-0.6.0-py3-none-any.whl
- Upload date:
- Size: 51.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10a845b167b0a7bc8db4f252433fabeff9873dcc8cfe35fdf70a11db489c1170
|
|
| MD5 |
7340d72c8dda45d1fc54e9c4248930a5
|
|
| BLAKE2b-256 |
50225af7af226b7703e7e06afe7688ddfd6a587bc96353a2c473f427c5628c96
|