Blueprint Modular App¶
Overview¶
The examples/recipes/blueprint_modular_app/ example demonstrates how to split a function app into
multiple files using func.Blueprint(). function_app.py is reduced to composition logic and registers
bp_health.py plus bp_users.py, keeping routing concerns isolated from app bootstrap code.
This modular approach becomes important as endpoint count grows. Teams can own separate blueprints,
write focused tests, and avoid a single monolithic function_app.py file that becomes hard to review.
When to Use¶
- Your app has multiple routes or domains and needs clean module boundaries.
- You want reusable route groups for internal platform patterns.
- You need maintainable structure for larger teams and code reviews.
Architecture¶
+----------------------+
| function_app.py |
| register_blueprint() |
+----------+-----------+
|
+-----------+-----------+
| |
v v
+----------+-----------+ +--------+------------+
| bp_health.py | | bp_users.py |
| GET /api/health | | GET /api/users |
+----------------------+ | GET /api/users/{id} |
| POST /api/users |
+---------------------+
Prerequisites¶
- Python 3.10+
- Azure Functions Core Tools v4
- HTTP client such as curl or Postman
- Local storage emulator for standard Functions runtime dependencies
Project Structure¶
examples/recipes/blueprint_modular_app/
|-- function_app.py
|-- bp_health.py
|-- bp_users.py
|-- host.json
|-- local.settings.json.example
|-- requirements.txt
`-- README.md
Implementation¶
The root file composes blueprints only. This keeps startup code explicit and easy to scan.
import azure.functions as func
from bp_health import bp as health_bp
from bp_users import bp as users_bp
app = func.FunctionApp()
app.register_blueprint(health_bp)
app.register_blueprint(users_bp)
bp_health.py owns a focused readiness endpoint and returns a stable JSON payload.
bp = func.Blueprint()
@bp.route(route="health", methods=["GET"])
def get_health(req: func.HttpRequest) -> func.HttpResponse:
del req
return func.HttpResponse(
body='{"status": "healthy"}',
mimetype="application/json",
status_code=200,
)
bp_users.py contains CRUD-like endpoints with validation and in-memory storage for simple local demos.
bp = func.Blueprint()
_users: dict[str, dict[str, Any]] = {}
@bp.route(route="users", methods=["POST"])
def create_user(req: func.HttpRequest) -> func.HttpResponse:
payload = req.get_json()
user = {"id": str(payload.get("id", "")).strip(), "name": str(payload.get("name", "")).strip()}
_users[user["id"]] = user
return func.HttpResponse(body=json.dumps(user), mimetype="application/json", status_code=201)
Run Locally¶
Expected Output¶
GET /api/health -> 200 {"status": "healthy"}
GET /api/users -> 200 {"users": []}
POST /api/users -> 201 {"id": "u1", "name": "Ada"}
GET /api/users/u1 -> 200 {"id": "u1", "name": "Ada"}
GET /api/users/missing -> 404 {"error": "user not found"}
Production Considerations¶
- Scaling: keep route modules stateless; replace in-memory dict with durable storage.
- Retries: HTTP handlers should return deterministic status codes for client retry policies.
- Idempotency: enforce idempotency keys for create operations when clients can retry POSTs.
- Observability: add per-blueprint logging and correlation IDs for route-level telemetry.
- Security: apply auth levels and input validation consistently across each blueprint module.