Skip to content

SQLAlchemy 2.0

Validate at the application boundary, then hand only proven data to SQLAlchemy. The DTO pattern below keeps validation rules out of your persistence layer and lets you reuse the same DTO across HTTP, queue, and CLI entry points.

Project: https://github.com/sqlalchemy/sqlalchemy

The integration

from typing import Annotated
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from monk import monk, validate
from monk.constraints import Email, Len
from monk.exceptions import ValidationError

# 1. The Database Model (Pure Persistence)
class Base(DeclarativeBase):
    pass

class UserDB(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True)
    username: Mapped[str]
    email: Mapped[str] = mapped_column(unique=True)

# 2. The DTO (Pure Validation)
@monk
class CreateUserDTO:
    username: Annotated[str, Len(min_len=3)]
    email: Annotated[str, Email]

# 3. The API / Service Handler
def register_user(payload: dict) -> UserDB:
    try:
        # Validate at the boundary
        safe_dto = validate(CreateUserDTO(**payload))
    except ValidationError as e:
        print("Request rejected:", e.flatten())
        raise

    # Hand pure data to the ORM
    new_user = UserDB(username=safe_dto.username, email=safe_dto.email)
    # session.add(new_user)
    # session.commit()
    return new_user