Getting Started
Install Fusion Framework for Python and write your first API
Installation
pip install fusion-frameworkScaffold a project with Fusion Tool so you get the standard layout (main.py, core/settings.py, sample products module, and environment files):
fusion init --lang python --name my-app --description "My Fusion API"
cd my-app
pip install fusion-frameworkProject layout (what fusion init creates)
├── main.py # entrypoint — always starts the app here
├── core/
│ └── settings.py
└── src/
└── modules/
└── products/
└── products.py # sample module — edit / copy this patternmain.py
The entrypoint imports your modules (so @route classes register), loads settings, registers optional middleware, then starts the server. Keep startup logic here — do not put listen() inside module files:
"""Entry point: register routes, middleware, and start the server."""
import src.modules.products.products # registers @route classes
from fusion_framework.app import FusionApp
from fusion_framework.config import get_settings, load_settings_module
# Global middleware (optional). Framework ships with none by default.
MIDDLEWARE: list = []
def main() -> None:
load_settings_module("settings")
app = FusionApp(get_settings())
for middleware in MIDDLEWARE:
app.use(middleware)
app.listen()
if __name__ == "__main__":
main()When you add another module, import it in main.py the same way. See Middleware and Config.
Sample products module
fusion init ships a small products API. You write handlers on a FusionBaseApi subclass and pass Swagger metadata on @route:
from fusion_framework.api import FusionBaseApi
from fusion_framework.route import route
from fusion_framework import status
@route(
"api/[module]/",
tags=["swagger"],
desc="Fusion Framework Api",
version="v1",
deprecated=False,
)
class ProductModule(FusionBaseApi):
"""Product management module."""
def get(self):
return self.response({"products_id": 12}, status=status.HTTP_SUCCESS)
def post(self):
return self.response({"products_id": 12}, status=status.HTTP_201_CREATED)
def delete(self):
return self.response({"products_id": 12}, status=status.HTTP_204_NO_CONTENT)
def patch(self):
return self.response({"products_id": 12}, status=status.HTTP_SUCCESS)[module] resolves from the class name (ProductModule → product), so this route becomes /api/product/.
Per-route Swagger options on @route:
| Argument | Purpose |
|---|---|
tags | OpenAPI tags (grouping in Swagger UI) |
desc | Operation / API description |
title | Optional title |
version | API version metadata |
deprecated | Mark the route deprecated in OpenAPI |
Global Swagger UI settings (path, auth schemes, UI options) live in fusion.<env>.json — see Commands & environments.
Run it
fusion command run:devThen open:
- API: http://127.0.0.1:8080
- Swagger UI: http://127.0.0.1:8080/swagger
Swagger is generated automatically from your @route modules. Use the UI to explore and call the sample products endpoints.
Status codes
Use the status module instead of raw integers:
from fusion_framework import status
status.HTTP_SUCCESS # 200
status.HTTP_201_CREATED # 201
status.HTTP_204_NO_CONTENT # 204
status.HTTP_404_NOT_FOUND # 404return self.response({"ok": True}, status=status.HTTP_SUCCESS)Handlers
Implement HTTP methods as usual: get, post, put, patch, delete.
Parameter binding
Arguments are taken from the method signature. The source depends on the parameter name:
- If the name matches a path parameter → path
- Else if the method is
POST/PUT/PATCHand the name appears in the JSON body → body - Else if the name appears in the query string → query
- Missing optional parameters (default or annotation) arrive as
None
from fusion_framework.api import FusionBaseApi
from fusion_framework.http import HTTPException
from fusion_framework.route import route
from fusion_framework import status
@route("api/[module]/{id}", tags=["items"], desc="Items by id")
class Items(FusionBaseApi):
def get(self, id: int):
return self.response({"id": id}, status=status.HTTP_SUCCESS)
def post(self, id: int, title: str = "untitled"):
# id ← path, title ← JSON body (optional via default)
return self.response(
{"id": id, "title": title},
status=status.HTTP_201_CREATED,
)
@route("api/[module]/", tags=["products"], desc="Products list")
class Products(FusionBaseApi):
def get(self, id: int):
# GET /api/products/?id=12
if not id:
raise HTTPException(400, {"message": "id is required"})
return self.response({"products_id": id}, status=status.HTTP_SUCCESS)Remember: put new modules under src/modules/... and import them from main.py. Leave app startup (load_settings_module / FusionApp / listen) only in main.py.
Details: Router.
Responses
Use self.response(body, status=status.HTTP_SUCCESS, **headers) for the response envelope. Dicts and lists are serialized as JSON by the core.
Errors
from fusion_framework.http import HTTPException
raise HTTPException(404, {"detail": "not found"})Async handlers
@route("/")
class Root(FusionBaseApi):
def get(self):
return self.response({"status": "ok"}, status=status.HTTP_SUCCESS)
async def post(self):
return self.response({"status": "async ok"}, status=status.HTTP_SUCCESS)Full guide: Async.
Configuration
Runtime settings come from fusion.<env>.json (FUSION_ENV, default dev). Load them in main.py with load_settings_module / get_settings.
Full guide: Config. Also see Commands & environments.
Middleware
No middleware runs by default. Register your own in main.py (MIDDLEWARE + app.use) or on @route(..., middleware=..., roles=...).
Full guide: Middleware.
Core APIs
| Symbol | Role |
|---|---|
FusionBaseApi | Request view (method, path, body, headers, params, query, state) and response(...) |
route(...) | Register a module; Swagger metadata + optional middleware / roles |
router(path) | Alias of route(path) without Swagger metadata |
status | HTTP status constants (HTTP_SUCCESS → 200, …) |
FusionApp / app.use / listen | App + global middleware — call from main.py |
load_settings_module / get_settings | Load fusion.<env>.json + core/settings.py |
HTTPException | Raise an HTTP error response |
Under the hood, PyO3 bridges to fusion-core for routing, binding, and serialization.