RavynΒΆ
The Ravyn class is the core of your application. It handles routing, middleware, settings, and ties everything together.
What You'll LearnΒΆ
- Creating a Ravyn application
- Configuration options
- Application state management
- Accessing settings
- Lifecycle management
Quick StartΒΆ
from ravyn import Gateway, Ravyn, get
@get("/")
def homepage() -> dict:
return {"message": "Hello, Ravyn!"}
app = Ravyn(
routes=[Gateway(handler=homepage)],
debug=True
)
How the application pieces fit togetherΒΆ
Ravyn instance
-> route tree (Gateway/Include/Router)
-> request pipeline (middleware, permissions, dependencies)
-> handler
-> response conversion
This is the core execution model you will see repeated across the framework.
Architecture at a glanceΒΆ
flowchart LR
Server["ASGI Server"] --> App["Ravyn"]
App --> RouteTree["Gateway / Include / Router"]
App --> Pipeline["Middleware / Interceptors / Permissions"]
RouteTree --> Handler["Handler / Controller Method"]
Handler --> Services["Service / DAO Layer"]
Services --> Storage["DB / Cache / External API"]
Handler --> Response["Response Serialization"]
For a detailed architectural walkthrough, see System Architecture.
Creating an ApplicationΒΆ
Minimal ApplicationΒΆ
from ravyn import Ravyn
app = Ravyn()
Route Requirement
While the code above assumes a valid application, a Ravyn application requires at least one route to be useful. Without routes, it will return 404 for every request.
Also, ensure your route handlers have explicit return types (e.g., def handler() -> dict:). This is crucial for data serialization and automatic documentation.
With RoutesΒΆ
from ravyn import Ravyn, Gateway, get
@get("/users")
def list_users() -> dict:
return {"users": []}
app = Ravyn(
routes=[Gateway(handler=list_users)]
)
With ConfigurationΒΆ
from ravyn import Ravyn
app = Ravyn(
title="My API",
version="1.0.0",
debug=True,
routes=[...]
)
Configuration ParametersΒΆ
Essential ParametersΒΆ
| Parameter | Type | Description |
|---|---|---|
routes |
list | List of Gateway, WebSocketGateway, Include |
debug |
bool | Enable debug mode (default: False) |
title |
str | API title for OpenAPI docs |
version |
str | API version for OpenAPI docs |
OpenAPI ParametersΒΆ
| Parameter | Type | Description |
|---|---|---|
description |
str | API description |
contact |
dict | Admin contact info |
license |
dict | License information |
servers |
list | Server configurations |
tags |
list | OpenAPI tags |
Security & MiddlewareΒΆ
| Parameter | Type | Description |
|---|---|---|
allowed_hosts |
list | Allowed host names |
cors_config |
CORSConfig | CORS configuration |
csrf_config |
CSRFConfig | CSRF protection |
session_config |
SessionConfig | Session management |
middleware |
list | Custom middleware |
Advanced ParametersΒΆ
| Parameter | Type | Description |
|---|---|---|
dependencies |
dict | Application-level dependencies |
interceptors |
list | Request interceptors |
permissions |
list | Permission classes |
exception_handlers |
dict | Custom exception handlers |
lifespan |
callable | Lifespan context manager |
Complete ExampleΒΆ
from ravyn import Ravyn, Gateway, Include, get
from ravyn import CORSConfig
@get("/health")
def health_check() -> dict:
return {"status": "healthy"}
@get("/users")
def list_users() -> dict:
return {"users": []}
app = Ravyn(
title="My API",
version="1.0.0",
description="A powerful API built with Ravyn",
debug=True,
# Routes
routes=[
Gateway(handler=health_check),
Include("/api", routes=[
Gateway(handler=list_users)
])
],
# CORS
cors_config=CORSConfig(
allow_origins=["*"],
allow_methods=["*"]
),
# Security
allowed_hosts=["localhost", "api.example.com"]
)
Application StateΒΆ
Store arbitrary data on the application instance:
Setting StateΒΆ
from ravyn import Ravyn
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: Ravyn):
# Startup
app.state.db = await connect_database()
app.state.cache = RedisCache()
yield
# Shutdown
await app.state.db.disconnect()
await app.state.cache.close()
app = Ravyn(lifespan=lifespan)
Accessing StateΒΆ
from ravyn import get, Request
@get("/users")
async def get_users(request: Request) -> dict:
# Access database from state
db = request.app.state.db
users = await db.fetch_all("SELECT * FROM users")
return {"users": users}
Accessing SettingsΒΆ
From RequestΒΆ
from ravyn import get, Request
@get("/config")
def get_config(request: Request) -> dict:
settings = request.app.settings
return {
"debug": settings.debug,
"title": settings.title
}
From Global SettingsΒΆ
from ravyn.conf import settings
# Access anywhere
print(settings.debug)
print(settings.title)
From conf ModuleΒΆ
from ravyn.conf.global_settings import RavynSettings
settings = RavynSettings()
print(settings.debug)
Lifecycle ManagementΒΆ
Startup and ShutdownΒΆ
async def startup():
print("Application starting...")
# Initialize resources
async def shutdown():
print("Application shutting down...")
# Cleanup resources
app = Ravyn(
on_startup=[startup],
on_shutdown=[shutdown]
)
Lifespan Context (Recommended)ΒΆ
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: Ravyn):
# Startup
print("Starting up...")
app.state.db = await connect_database()
yield # Application runs
# Shutdown
print("Shutting down...")
await app.state.db.disconnect()
app = Ravyn(lifespan=lifespan)
Tip
Use lifespan instead of on_startup/on_shutdown for better resource management.
Common PatternsΒΆ
Pattern 1: API with DatabaseΒΆ
from ravyn import Ravyn, get
from contextlib import asynccontextmanager
@asynccontextmanager
async def lifespan(app: Ravyn):
app.state.db = await connect_database()
yield
await app.state.db.disconnect()
@get("/users")
async def get_users(request: Request) -> list:
return await request.app.state.db.fetch_all("SELECT * FROM users")
app = Ravyn(
routes=[Gateway(handler=get_users)],
lifespan=lifespan
)
Pattern 2: MicroserviceΒΆ
from ravyn import Ravyn, Include
app = Ravyn(
title="User Service",
version="1.0.0",
routes=[
Include("/api/v1", routes=v1_routes),
Include("/api/v2", routes=v2_routes)
],
cors_config=CORSConfig(allow_origins=["*"])
)
Pattern 3: With SettingsΒΆ
from ravyn import Ravyn, RavynSettings
class AppSettings(RavynSettings):
title: str = "My API"
debug: bool = True
database_url: str = "postgresql://..."
app = Ravyn(settings_module=AppSettings)
Common Pitfalls & FixesΒΆ
Pitfall 1: Forgetting to Add RoutesΒΆ
Problem: No routes defined.
# Wrong - no routes
app = Ravyn()
Solution: Add routes:
# Correct
app = Ravyn(
routes=[Gateway(handler=homepage)]
)
Pitfall 2: Using Both Lifespan and on_startupΒΆ
Problem: Mixing lifecycle approaches.
# Wrong - using both
app = Ravyn(
lifespan=lifespan,
on_startup=[startup] # Don't mix!
)
Solution: Use one or the other:
# Correct
app = Ravyn(lifespan=lifespan)
Pitfall 3: Accessing State Before InitializationΒΆ
Problem: State not set up yet.
# Wrong - state not initialized
app = Ravyn()
print(app.state.db) # Error!
Solution: Initialize in lifespan:
# Correct
@asynccontextmanager
async def lifespan(app: Ravyn):
app.state.db = await connect_database()
yield
app = Ravyn(lifespan=lifespan)
Best PracticesΒΆ
1. Use Settings for ConfigurationΒΆ
# Good - settings-based
class AppSettings(RavynSettings):
title: str = "My API"
debug: bool = False
app = Ravyn(settings_module=AppSettings)
2. Organize Routes with IncludeΒΆ
# Good - organized routes
app = Ravyn(
routes=[
Include("/api/users", routes=user_routes),
Include("/api/products", routes=product_routes)
]
)
3. Use Lifespan for ResourcesΒΆ
# Good - proper resource management
@asynccontextmanager
async def lifespan(app: Ravyn):
app.state.db = await connect_database()
yield
await app.state.db.disconnect()
app = Ravyn(lifespan=lifespan)
Next StepsΒΆ
Now that you understand the Ravyn application class, explore:
- Settings - Application configuration
- Routing - Route configuration
- Middleware - Request processing
- Lifespan Events - Application lifecycle