Extended Robyn app example.
Async REST API for managing crime records. Built with Robyn, Clean Architecture, production-ready tooling.
- Features
- Quick Start
- Project Structure
- API Endpoints
- Architecture
- Logging System
- Configuration
- Development
- License
-
Crime Record Management:
- Create, read, update, and delete crime records
- Paginated listing with configurable skip/limit
- Full request/response validation with Pydantic v2
- Structured error responses with request tracing
-
Async & High Performance:
- Async Python web server (Robyn + Actix Rust runtime)
- Async database operations (SQLAlchemy + aiosqlite)
- WAL-mode SQLite with performance tuning
- Request duration tracking in nanoseconds
-
Clean Architecture:
- Strict separation of concerns (Domain, Database, Endpoints, Config)
- Repository pattern with pure async functions
- DI/IoC container with lazy loading and request-scoped providers
- Interface-based design with adapter pattern
-
Enterprise Logging:
- Structured logging with
structlog - JSON output for production, colored console for development
- Context binding with automatic
request_idinjection - File rotation with size limits
- Third-party logger hijacking (SQLAlchemy, Robyn, Pydantic, etc.)
- Structured logging with
-
Production Ready:
- Full type hints with Python 3.14
- Ruff for linting and formatting (all rules enabled)
tyfor strict type checking- Multi-stage Dockerfile with non-root user
- Health check endpoint
- CORS configuration
- Bearer token authentication (extensible)
- Python 3.14+
- uv
- Docker (optional)
# Clone the repository
git clone https://github.com/script-logic/robyn-app-example-extended.git
cd robyn_app_example_extended
# Install with uv
uv sync# Start the server
uv run python -m robyn_example
# Using Docker
docker-compose up
# Using Just
just runThe API will be available at http://127.0.0.1:8082.
βββ local_database/ # SQLite database (WAL mode)
β βββ database.db
βββ logs/ # Application logs (rotating)
βββ src/
β βββ robyn_example/
β βββ adapters/ # Adapter layer
β β βββ adapters.py # Config β LoggerConfig adapter
β βββ config/ # Configuration
β β βββ models/ # Settings models
β β β βββ application_settings.py
β β β βββ cors_settings.py
β β β βββ database_settings.py
β β β βββ filesystem_settings.py
β β β βββ logger_settings.py
β β βββ app_config.py # Pydantic-settings root
β βββ database/ # Database layer
β β βββ crime_repository.py # Pure async repository functions
β β βββ db_manager.py # Engine & session management
β β βββ models.py # SQLAlchemy 2.0 ORM models
β βββ di/ # Dependency Injection
β β βββ _proxy_ioc.py # Lazy-loaded proxy container
β β βββ _real_ioc.py # Real DI container
β βββ domain/ # Domain entities
β β βββ entities.py # CrimeEntity, RequestMiddlewareEntity
β βββ logger/ # Structured logging system
β β βββ handlers.py # Console & file handlers
β β βββ interfaces.py # LoggerConfig dataclass
β β βββ processors.py # Log processors & cleaners
β β βββ renderers.py # JSON & console renderers
β β βββ setup.py # Logging initialization
β βββ robyn/ # Web layer
β β βββ endpoints/
β β β βββ api_v1/ # API v1 endpoints
β β β β βββ endpoints.py # CRUD route handlers
β β β β βββ enums.py # Path parameter enums
β β β β βββ schemas.py # Request/response schemas
β β β βββ exceptions/ # Error handling
β β β β βββ exceptions_handler.py
β β β β βββ schemas.py # Error response models
β β β βββ helpers/ # Parsers & policies
β β β βββ health.py # Health check endpoint
β β βββ auth.py # Authentication handler
β β βββ runner.py # App bootstrap & middleware
β βββ __main__.py # Entry point
βββ pyproject.toml # Project metadata & dependencies
βββ docker-compose.yml # Docker Compose setup
βββ Dockerfile # Multi-stage Docker build
βββ Justfile # Task runner
βββ ruff.toml # Linter configuration
βββ ty.toml # Type checker configuration
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST |
/crime/add |
No | Create a new crime record |
GET |
/crimes/get?skip=0&limit=100 |
No | List crimes (paginated) |
GET |
/crime/:crime_id |
Bearer | Get crime by ID |
PUT |
/crime/update/:crime_id |
No | Update crime by ID |
DELETE |
/crime/:crime_id |
No | Delete crime by ID |
Create Crime:
POST /api/v1/crime/add
{
"type": "Robbery",
"description": "Bank robbery at Main Street",
"location": "Downtown",
"suspect_name": "John Doe",
"date_time": "2026-05-14T12:00:00",
"latitude": 40.7128,
"longitude": -74.0060
}Response:
{
"id": 1,
"type": "Robbery",
"description": "Bank robbery at Main Street",
"location": "Downtown",
"suspect_name": "John Doe",
"date_time": "2026-05-14T12:00:00",
"latitude": 40.7128,
"longitude": -74.0060,
"created_at": "2026-05-14T12:00:00+00:00",
"updated_at": null
}Error Response (500):
{
"status_code": 500,
"description": "Internal server error",
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}βββββββββββββββββββββββββββββββββββββββ
β robyn/ (Web Layer) β
β endpoints/ auth/ runner.py β
βββββββββββββββββββββββββββββββββββββββ€
β database/ (Data Layer) β
β crime_repository.py db_manager.py β
βββββββββββββββββββββββββββββββββββββββ€
β domain/ (Domain Layer) β
β entities.py β
βββββββββββββββββββββββββββββββββββββββ€
β config/ di/ adapters/ logger/ β
β (Infrastructure & Cross-cutting) β
βββββββββββββββββββββββββββββββββββββββ
- Pure Repository Functions: Database operations are async functions, not class methods. Session is passed explicitly β no hidden state, easy to test.
- Lazy DI Proxy: The
Ioccontainer uses a proxy pattern withLazyProviderto avoid circular imports and enable lazy resolution. - ContextVar-based Request Tracing:
request_idis stored incontextvars.ContextVarand propagated to middleware, exception handlers, and error responses without passing through function signatures. - Adapter Pattern:
LoggerConfigAdaptertransformsAppConfiginto aLoggerConfigdataclass β keeps logger module independent of config structure. - SQLite WAL Mode: Write-Ahead Logging enables concurrent reads without blocking, with performance PRAGMAs tuned for API workloads.
A sophisticated, production-ready logging system built with structlog.
- Structured Logging: All logs are structured events with automatic context injection (filename, function, line number, thread, process).
- Dual Output:
- Development: Colored console output with padded event names.
- Production: JSON format with
orjsonserialization for log aggregation.
- Request Tracing: Every request gets a UUID
request_idthat appears in all related logs and error responses. - Middleware Logging: Request body, headers, IP, and identity are logged at DEBUG level; duration is tracked in nanoseconds.
- File Rotation: Configurable log rotation with size limits and backup count.
- Third-party Hijacking: Automatically configures log levels for SQLAlchemy, Robyn, Pydantic, aiosqlite, and more.
Console (Development):
2026-05-14 12:00:00 [info ] request_id=a1b2c3d4... runner.py:45
2026-05-14 12:00:01 [info ] request_id=a1b2c3d4... request_path=/api/v1/crime/1 response_duration_ns=1234567 runner.py:58
JSON (Production):
{"event": "request_id=a1b2c3d4...", "logger": "robyn_example.robyn.runner", "level": "info", "timestamp": "2026-05-14T12:00:00", "filename": "runner.py", "lineno": 45}All settings can be overridden via environment variables with __ as nested delimiter:
ENV_FILE_NAME=".env.prod"
APP__TITLE="Crime API Production"
APP__HOST="0.0.0.0"
APP__PORT=8080
DB__DB_DIR="/data/database"
DB__ECHO=false
LOG__LOG_LEVEL=20
LOG__ENABLE_FILE_LOGGING=true# Application
app.title = "Robyn Example"
app.host = "127.0.0.1"
app.port = 8082
app.client_timeout_sec = 30
app.keep_alive_timeout_sec = 20
# Database
db.db_schema = "sqlite+aiosqlite"
db.db_dir = "./local_database"
db.db_name = "database.db"
db.pool_size = 3
# Logging
log.log_level = 10 # 10 means "DEBUG", 20 means "INFO", etc
log.console_colors = True
log.enable_file_logging = True
# File System
filesys.logs_dir = "./logs"
filesys.max_log_file_size_mb = 10
filesys.log_backup_count = 5# Install with dev dependencies
uv sync --group dev
# Run linter & formatter
just lint- Ruff: All rules enabled (
select = ["ALL", "ANN", "I"]), line length 79, Google-style docstrings. - ty: Strict type checking with
all = "error".
# Build and run
docker-compose up --build
# Rebuild
docker-compose down && docker-compose build && docker-compose up
# Using Just
just buildThe Docker image uses a multi-stage build with uv for fast dependency installation and runs as a non-root user.
MIT License β free to use and modify.