init
This commit is contained in:
10
app/presentation/api/v1/health.py
Normal file
10
app/presentation/api/v1/health.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
router = APIRouter(prefix="/health", tags=["health"])
|
||||
|
||||
|
||||
@router.get("")
|
||||
async def health():
|
||||
return {"status": "ok"}
|
||||
44
app/presentation/api/v1/users.py
Normal file
44
app/presentation/api/v1/users.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
|
||||
from app.application.users.use_cases.create_user import (
|
||||
CreateUserCommand,
|
||||
CreateUserUseCase,
|
||||
)
|
||||
from app.application.users.use_cases.get_user import GetUserQuery, GetUserUseCase
|
||||
from app.domain.users.exceptions import InvalidEmail, UserAlreadyExists, UserNotFound
|
||||
from app.presentation.dependencies.users import get_create_user_uc, get_get_user_uc
|
||||
from app.presentation.schemas.users import CreateUserRequest, UserResponse
|
||||
|
||||
router = APIRouter(prefix="/users", tags=["users"])
|
||||
|
||||
|
||||
@router.post("", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_user(
|
||||
req: CreateUserRequest,
|
||||
uc: CreateUserUseCase = Depends(get_create_user_uc),
|
||||
) -> UserResponse:
|
||||
try:
|
||||
dto = await uc.execute(
|
||||
CreateUserCommand(email=str(req.email), full_name=req.full_name)
|
||||
)
|
||||
return UserResponse(**dto.__dict__)
|
||||
except InvalidEmail as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except UserAlreadyExists as e:
|
||||
raise HTTPException(status_code=409, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/{user_id}", response_model=UserResponse)
|
||||
async def get_user(
|
||||
user_id: UUID,
|
||||
uc: GetUserUseCase = Depends(get_get_user_uc),
|
||||
) -> UserResponse:
|
||||
try:
|
||||
dto = await uc.execute(GetUserQuery(user_id=user_id))
|
||||
return UserResponse(**dto.__dict__)
|
||||
except UserNotFound as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
30
app/presentation/dependencies/users.py
Normal file
30
app/presentation/dependencies/users.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import Depends
|
||||
|
||||
from app.application.users.use_cases.create_user import CreateUserUseCase
|
||||
from app.application.users.use_cases.get_user import GetUserUseCase
|
||||
from app.infrastructure.db.sqlalchemy.session import get_sessionmaker
|
||||
from app.infrastructure.db.sqlalchemy.uow import SqlAlchemyUnitOfWork
|
||||
from app.infrastructure.integrations.email.smtp_sender import SmtpWelcomeEmailSender
|
||||
|
||||
|
||||
def get_uow() -> SqlAlchemyUnitOfWork:
|
||||
return SqlAlchemyUnitOfWork(get_sessionmaker())
|
||||
|
||||
|
||||
def get_email_sender() -> SmtpWelcomeEmailSender:
|
||||
return SmtpWelcomeEmailSender()
|
||||
|
||||
|
||||
def get_create_user_uc(
|
||||
uow: SqlAlchemyUnitOfWork = Depends(get_uow),
|
||||
email_sender: SmtpWelcomeEmailSender = Depends(get_email_sender),
|
||||
) -> CreateUserUseCase:
|
||||
return CreateUserUseCase(uow=uow, welcome_email_sender=email_sender)
|
||||
|
||||
|
||||
def get_get_user_uc(
|
||||
uow: SqlAlchemyUnitOfWork = Depends(get_uow),
|
||||
) -> GetUserUseCase:
|
||||
return GetUserUseCase(uow=uow)
|
||||
28
app/presentation/main.py
Normal file
28
app/presentation/main.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
from app.infrastructure.db.sqlalchemy.models import Base
|
||||
from app.infrastructure.db.sqlalchemy.session import get_engine
|
||||
from app.presentation.api.v1.health import router as health_router
|
||||
from app.presentation.api.v1.users import router as users_router
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
app = FastAPI(title="DDD Onion FastAPI Demo", version="1.0.0")
|
||||
|
||||
app.include_router(health_router)
|
||||
app.include_router(users_router)
|
||||
|
||||
@app.on_event("startup")
|
||||
async def on_startup() -> None:
|
||||
# демо-миграция: создать таблицы при старте
|
||||
# в проде делай Alembic, но файл models.py уже готов.
|
||||
engine = get_engine()
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
app = create_app()
|
||||
19
app/presentation/schemas/users.py
Normal file
19
app/presentation/schemas/users.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
|
||||
|
||||
class CreateUserRequest(BaseModel):
|
||||
email: EmailStr
|
||||
full_name: str = Field(min_length=1, max_length=200)
|
||||
|
||||
|
||||
class UserResponse(BaseModel):
|
||||
id: UUID
|
||||
email: EmailStr
|
||||
full_name: str
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
Reference in New Issue
Block a user