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.

FeatureDetail
GET /Service name, version, and running status — auto-registered
GET /healthUptime seconds, name, version, timestamp — auto-registered
GET /docsFastAPI Swagger UI — auto-registered by FastAPI
CORSConfigurable origins via config.ini — defaults to *
Exception handlingAll HTTP error types return consistent JSON
DB middlewareAuto-wired DbMiddleware when enable_database=True
CacheAuto-wired Redis cache when enable_cache=True
Lifecycle hooksstartup() and shutdown() overridable per service
CLI args--host, --port, --reload, --workers, --log-level
Dependencies: viveka-setu requires viveka-grantha for config, logging, and cache. viveka-kosha is optional — install viveka-setu[database] to enable DB support.

Installation

$ pip install viveka-setu

With database support:

$ pip install "viveka-setu[database]"

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

PrioritySourceExample
1 (highest)CLI argument--port 9000
2config.ini [server] sectionport = 9000
3 (lowest)Hardcoded default127.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,
)
FieldTypeDefaultDescription
namestrrequiredService name — shown in logs, health, Swagger
versionstrrequiredService version — shown in health and root route
descriptionstr""Shown in Swagger UI description
enable_databaseboolFalseInitializes DatabaseSessionFactory and DbMiddleware
enable_cacheboolFalseInitializes 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

RouteResponse
GET /{"service", "version", "status": "running"}
GET /healthVivekaServerHealthStatus — status, name, version, uptime, timestamp
GET /docsSwagger UI (FastAPI built-in)
GET /redocReDoc 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
ExceptionHTTPError Code
NotFoundException404NOT_FOUND
ValidationException400VALIDATION_ERROR
UnauthorizedException401UNAUTHORIZED
ForbiddenException403FORBIDDEN
InternalServerException500INTERNAL_ERROR
RateLimitException429RATE_LIMIT_EXCEEDED
BudgetExceededException402BUDGET_EXCEEDED
TimeoutException504TIMEOUT_ERROR
ProviderException502PROVIDER_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

ArgumentDefaultDescription
--host127.0.0.1Bind address
--port8000Bind port
--reloadfalseEnable auto-reload (development only)
--workers1Number of Uvicorn worker processes (ignored when --reload)
--log-levelinfodebug / 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
← viveka-kosha Docs ← viveka-grantha Docs Back to Home →