viveka-setu v0.1.0
Server Application Factory
FastAPI + Uvicorn application factory for Viveka services — built-in health, CORS, exception handling, and lifecycle management in under ten lines of code.
Overview
viveka-setu is the equivalent of Spring Boot's embedded server + @SpringBootApplication. It wraps FastAPI and Uvicorn so you focus on business logic, not server boilerplate.
| Feature | Detail |
|---|---|
| GET / | Service name, version, and running status — auto-registered |
| GET /health | Uptime seconds, name, version, timestamp — auto-registered |
| GET /docs | FastAPI Swagger UI — auto-registered by FastAPI |
| CORS | Configurable origins via config.ini — defaults to * |
| Exception handling | All HTTP error types return consistent JSON |
| DB middleware | Auto-wired DbMiddleware when enable_database=True |
| Cache | Auto-wired Redis cache when enable_cache=True |
| Lifecycle hooks | startup() and shutdown() overridable per service |
| CLI args | --host, --port, --reload, --workers, --log-level |
viveka-setu[database] to enable DB support.
Installation
With database support:
Quickstart
from viveka_server import VivekaApp, VivekaServer, VivekaAppConfig
app = VivekaApp(VivekaAppConfig(name="my-service", version="1.0.0"))
server = VivekaServer(app)
server.run()
Your service starts at http://127.0.0.1:8000 with:
GET / → {"service": "my-service", "version": "1.0.0", "status": "running"}
GET /health → {"status": "healthy", "uptime_seconds": 3.2, ...}
GET /docs → Swagger UI
Configuration
All server settings read from config.ini. CLI args override config.ini values.
[server]
host = 0.0.0.0
port = 8080
reload = false
workers = 4
log_level = info
[api]
cors_origins = https://myapp.com, https://admin.myapp.com
[logging]
level = INFO
file_path = logs/service.log
[database]
url = postgresql+asyncpg://user:pass@localhost/mydb
pool_size = 10
max_overflow = 20
[cache]
enabled = true
url = redis://localhost:6379/0
default_ttl = 3600
Config priority order
| Priority | Source | Example |
|---|---|---|
| 1 (highest) | CLI argument | --port 9000 |
| 2 | config.ini [server] section | port = 9000 |
| 3 (lowest) | Hardcoded default | 127.0.0.1 : 8000 |
VivekaAppConfig
Dataclass that defines the service identity and which infrastructure components to enable.
from viveka_server import VivekaAppConfig
config = VivekaAppConfig(
name = "order-service",
version = "2.1.0",
description = "Handles order lifecycle",
enable_database = True,
enable_cache = True,
)
| Field | Type | Default | Description |
|---|---|---|---|
| name | str | required | Service name — shown in logs, health, Swagger |
| version | str | required | Service version — shown in health and root route |
| description | str | "" | Shown in Swagger UI description |
| enable_database | bool | False | Initializes DatabaseSessionFactory and DbMiddleware |
| enable_cache | bool | False | Initializes VivekaCacheManager with Redis |
VivekaApp
Application lifecycle manager. Initializes logging, DB engine, and cache on construction. Override startup() and shutdown() for custom logic.
from viveka_server import VivekaApp, VivekaAppConfig
class MyApp(VivekaApp):
async def startup(self) -> None:
await super().startup()
# load ML models, warm caches, seed data
self.logger.info("Custom startup complete")
async def shutdown(self) -> None:
# flush buffers, close connections
self.logger.info("Custom shutdown complete")
await super().shutdown()
VivekaServer
Wraps FastAPI + Uvicorn. Registers middleware, exception handlers, and default routes. Pass a VivekaApp instance to the constructor.
Default Routes
| Route | Response |
|---|---|
| GET / | {"service", "version", "status": "running"} |
| GET /health | VivekaServerHealthStatus — status, name, version, uptime, timestamp |
| GET /docs | Swagger UI (FastAPI built-in) |
| GET /redoc | ReDoc UI (FastAPI built-in) |
Adding Custom Routes
from fastapi import APIRouter
from viveka_server import VivekaServer, VivekaApp, VivekaAppConfig
class OrderServer(VivekaServer):
def build_routes(self, router: APIRouter) -> APIRouter:
@router.get("/api/v1/orders")
async def list_orders():
return []
@router.post("/api/v1/orders")
async def create_order(order: OrderRequest):
return await order_service.create(order)
return router
app = MyApp(VivekaAppConfig(name="order-service", version="1.0.0"))
server = OrderServer(app)
server.run()
Lifecycle Hooks
The server calls VivekaApp.startup() when FastAPI's lifespan starts and shutdown() when it ends. Always call super() to preserve base behaviour.
Server starts
│
▼
FastAPI lifespan begins
│── VivekaApp.startup() ← your custom logic here
▼
Routes serve requests
│
▼
Server shuts down (Ctrl+C / SIGTERM)
└── VivekaApp.shutdown() ← your custom cleanup here
Exception Handling
All VivekaAPIException subclasses are caught globally and returned as consistent JSON:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "User 42 not found",
"details": {}
}
}
from viveka_server import NotFoundException, UnauthorizedException
@router.get("/users/{user_id}")
async def get_user(user_id: int):
user = await user_repo.get(user_id)
if not user:
raise NotFoundException(f"User {user_id} not found")
return user
| Exception | HTTP | Error Code |
|---|---|---|
| NotFoundException | 404 | NOT_FOUND |
| ValidationException | 400 | VALIDATION_ERROR |
| UnauthorizedException | 401 | UNAUTHORIZED |
| ForbiddenException | 403 | FORBIDDEN |
| InternalServerException | 500 | INTERNAL_ERROR |
| RateLimitException | 429 | RATE_LIMIT_EXCEEDED |
| BudgetExceededException | 402 | BUDGET_EXCEEDED |
| TimeoutException | 504 | TIMEOUT_ERROR |
| ProviderException | 502 | PROVIDER_ERROR |
Database & Cache
app = VivekaApp(VivekaAppConfig(
name = "data-service",
version = "1.0.0",
enable_database = True, # reads [database] from config.ini
enable_cache = True, # reads [cache] from config.ini
))
When enable_database=True, DatabaseSessionFactory (from viveka-kosha) is initialised and DbMiddleware is auto-registered on the FastAPI app — every HTTP request gets its own AsyncSession.
When enable_cache=True, VivekaCacheManager is initialised with RedisCacheService — the @cacheable and @cache_evict decorators from viveka-kosha work automatically.
CLI Arguments
| Argument | Default | Description |
|---|---|---|
| --host | 127.0.0.1 | Bind address |
| --port | 8000 | Bind port |
| --reload | false | Enable auto-reload (development only) |
| --workers | 1 | Number of Uvicorn worker processes (ignored when --reload) |
| --log-level | info | debug / info / warning / error / critical |
python main.py --host 0.0.0.0 --port 8080 --workers 4
python main.py --reload
python main.py --log-level debug