Middleware System Demo¶
Cello ships with a suite of built-in middleware that you can activate with a single method call on the App instance. This example shows how to layer CORS handling, structured logging, and gzip compression together while exploring the effect each middleware has on real HTTP requests. It also demonstrates how Blueprint groups share the same middleware stack automatically.
Features Demonstrated¶
app.enable_cors()— allowlist-based CORS with automatic preflight handlingapp.enable_logging()— per-request structured logging to stdoutapp.enable_compression(min_size=…)— transparent gzip compression for large responses- Custom response headers via
Response.set_header() - Cache-control and ETag headers for cacheable endpoints
Blueprintroute grouping under a shared/apiprefix- Manual
OPTIONSpreflight route withResponse.no_content()
Complete Source Code¶
#!/usr/bin/env python3
"""
Middleware System Demo for Cello v1.0.1.
Run with: python examples/middleware_demo.py
Then test with:
curl -v http://127.0.0.1:8000/
curl -H "Origin: https://example.com" http://127.0.0.1:8000/
"""
from cello import App, Blueprint, Response
app = App()
app.enable_cors(origins=["https://example.com", "https://app.example.com", "http://localhost:3000"])
app.enable_logging()
app.enable_compression(min_size=1024)
@app.get("/")
def home(request):
return {"message": "Cello Middleware Demo", "version": "1.0.1",
"enabled_middleware": ["CORS", "Logging", "Compression"]}
@app.get("/cors-demo")
def cors_demo(request):
origin = request.get_header("Origin")
return {"message": "CORS is enabled", "your_origin": origin,
"allowed_origins": ["https://example.com", "http://localhost:3000"]}
@app.options("/cors-demo")
def cors_preflight(request):
return Response.no_content()
@app.get("/compression-demo")
def compression_demo(request):
return {"items": [{"id": i, "name": f"Item {i}", "description": f"Desc for item {i}" * 10} for i in range(100)]}
@app.get("/request-info")
def request_info(request):
return {"method": request.method, "path": request.path,
"headers": {"content-type": request.get_header("Content-Type"), "user-agent": request.get_header("User-Agent")}}
@app.post("/echo")
def echo_request(request):
content_type = request.get_header("Content-Type") or ""
if "application/json" in content_type:
return {"received_json": request.json()}
return {"received_text": request.text()}
api = Blueprint("/api", name="api")
@api.get("/data")
def api_data(request):
return {"data": [{"id": 1, "value": "Item 1"}, {"id": 2, "value": "Item 2"}], "middleware_active": True}
@api.get("/users")
def api_users(request):
return {"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}
app.register_blueprint(api)
@app.get("/custom-headers")
def custom_headers(request):
response = Response.json({"message": "Response with custom headers"})
response.set_header("X-Custom-Header", "custom-value")
response.set_header("X-Powered-By", "Cello/1.0.1")
return response
@app.get("/cache-headers")
def cache_headers(request):
response = Response.json({"message": "Cacheable response"})
response.set_header("Cache-Control", "public, max-age=3600")
response.set_header("ETag", '"abc123"')
return response
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8000)
Running This Example¶
Key Concepts¶
- Middleware order matters — CORS headers are injected before logging writes its output, so the log line always reflects the final response status.
enable_compression(min_size=1024)— responses smaller than 1 KB are sent as-is; only larger payloads are gzip-encoded, keeping small API calls lightweight.- Blueprint registration — calling
app.register_blueprint(api)mounts all routes defined on the blueprint under/apiand ensures they inherit every middleware already attached toapp. Response.no_content()— returns a204 No Contentresponse, which is the correct reply to a CORS preflightOPTIONSrequest.Response.set_header()— lets you attach arbitrary HTTP headers to a response object without leaving the handler function, keeping header logic close to the business logic that produces it.