Core¶
Core infrastructure modules shared across the entire application.
Configuration¶
Application settings loaded from environment variables via Pydantic Settings.
Settings Class¶
from pydantic_settings import BaseSettings
from pydantic import computed_field
from pydantic_core import MultiHostUrl
class Settings(BaseSettings):
# Environment
ENV: Environment = Environment.development # development | test | production
LOG_LEVEL: str = "INFO"
# Database
POSTGRES_DRIVER: str = "postgresql+asyncpg"
POSTGRES_HOST: str = "localhost"
POSTGRES_PORT: int = 5432
POSTGRES_USER: str = "postgres"
POSTGRES_PASSWORD: str = "postgres"
POSTGRES_DB: str = "app_db"
@computed_field
@property
def DATABASE_URL(self) -> PostgresDsn:
# Constructs database URL from POSTGRES_* components
...
# Observability
OTEL_ENABLED: bool = True
# Networking
ALLOWED_HOSTS: list[str] = ["localhost", "127.0.0.1", "test", "*.orb.local"]
BACKEND_CORS_ORIGINS: list[str] = [
"http://localhost:3000",
"http://localhost:8000",
]
All settings use the QUOIN_ prefix (e.g., QUOIN_POSTGRES_HOST).
Usage:
from app.core.config import settings
database_url = settings.DATABASE_URL
is_production = settings.ENV == "production"
Source: app/core/config.py
Metadata¶
Static application identity used in OpenAPI parameters and the root page template.
from app.core.metadata import (
APP_NAME,
APP_DESCRIPTION,
VERSION,
REPOSITORY_URL,
COPYRIGHT_OWNER,
)
Source: app/core/metadata.py
Logging¶
Structured logging configuration powered by Structlog. Initialized first during application startup.
setup_logging¶
def setup_logging() -> None:
structlog.configure(
processors=[
structlog.contextvars.merge_contextvars,
structlog.processors.add_log_level,
structlog.processors.TimeStamper(fmt="iso"),
structlog.dev.ConsoleRenderer() # dev
],
)
Source: app/core/logging.py
Exceptions¶
Domain exception classes that map business errors to HTTP status codes.
All inherit from QuoinError.
QuoinError¶
Base class for all application exceptions.
from app.core.exceptions import QuoinError
class QuoinError(Exception):
"""Base class for application exceptions."""
def __init__(
self,
message: str,
status_code: int = 500,
headers: dict[str, str] | None = None,
) -> None:
self.message = message
self.status_code = status_code
self.headers = headers
Subclasses¶
| Class | Status | Default Message |
|---|---|---|
BadRequestError |
400 | "Bad Request" |
ForbiddenError |
403 | "Forbidden" |
NotFoundError |
404 | "Not Found" |
ConflictError |
409 | "Conflict" |
InternalServerError |
500 | "Internal Server Error" |
QuoinRequestValidationError |
422 | (Pydantic errors, internal) |
Usage:
from app.core.exceptions import NotFoundError, ConflictError
raise NotFoundError(message="User not found")
raise ConflictError(message="Email already registered")
Source: app/core/exceptions.py
Exception Handlers¶
Converts QuoinError domain exceptions to JSON HTTP responses.
Registered with the FastAPI app during startup.
quoin_exception_handler¶
async def quoin_exception_handler(
request: Request, exc: QuoinError
) -> JSONResponse:
return JSONResponse(
status_code=exc.status_code,
content={"detail": exc.message},
headers=exc.headers,
)
validation_exception_handler¶
Converts Pydantic ValidationError to 422 JSON responses.
async def validation_exception_handler(
request: Request, exc: ValidationError
) -> JSONResponse:
return JSONResponse(
status_code=422,
content={"detail": exc.errors()},
)
add_exception_handlers¶
Registers both handlers with the application.
def add_exception_handlers(app: FastAPI) -> None:
app.add_exception_handler(QuoinError, quoin_exception_handler)
app.add_exception_handler(ValidationError, validation_exception_handler)
Source: app/core/exception_handlers.py
Middlewares¶
Request-level processing applied before routes are hit.
configure_middlewares¶
def configure_middlewares(app: FastAPI) -> None:
app.add_middleware(
CORSMiddleware,
allow_origins=settings.BACKEND_CORS_ORIGINS,
allow_methods=["*"],
allow_headers=["*"],
)
Allowed origins are configured via QUOIN_BACKEND_CORS_ORIGINS
(defaults to localhost:3000 and localhost:8000).
Source: app/core/middlewares.py
Telemetry¶
OpenTelemetry instrumentation for distributed tracing. Added last during application startup.
setup_opentelemetry¶
def setup_opentelemetry(app: FastAPI) -> None:
if not settings.OTEL_ENABLED:
return
FastAPIInstrumentor.instrument_app(app)
SQLAlchemyInstrumentor().instrument()
Disable with QUOIN_OTEL_ENABLED=False in .env.
Source: app/core/telemetry.py
See Also¶
- Configuration Guide — Environment setup
- Error Handling Guide — Exception patterns
- Observability Guide — Logging and tracing