StartFromBegining
parent
08e6aa5cb1
commit
b733a6bf9a
46
api/app.py
46
api/app.py
|
@ -1,46 +0,0 @@
|
|||
from collections.abc import AsyncIterable
|
||||
|
||||
from fastapi import FastAPI
|
||||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
||||
|
||||
from api.depends import ( # new_unit_of_work,; new_user_repository,; new_user_service,
|
||||
create_engine,
|
||||
create_session_maker,
|
||||
new_session,
|
||||
)
|
||||
from api.models import BaseModel
|
||||
|
||||
|
||||
async def lifespan(app: FastAPI) -> AsyncIterable[None]:
|
||||
engine = app.dependency_overrides[AsyncEngine]()
|
||||
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(BaseModel.metadata.create_all)
|
||||
|
||||
yield
|
||||
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(BaseModel.metadata.drop_all)
|
||||
|
||||
|
||||
def init_dependencies(app: FastAPI) -> None:
|
||||
app.dependency_overrides[AsyncEngine] = create_engine
|
||||
app.dependency_overrides[async_sessionmaker[AsyncSession]] = create_session_maker
|
||||
app.dependency_overrides[AsyncSession] = new_session
|
||||
# app.dependency_overrides[UserRepository] = new_user_repository
|
||||
# app.dependency_overrides[UnitOfWork] = new_unit_of_work
|
||||
# app.dependency_overrides[UserService] = new_user_service
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
app = FastAPI(
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
# app.include_router(user_router)
|
||||
|
||||
init_dependencies(app)
|
||||
return app
|
||||
|
||||
|
||||
app = create_app()
|
|
@ -0,0 +1,3 @@
|
|||
from .main import app_factory
|
||||
|
||||
__all__ = ("app_factory",)
|
|
@ -0,0 +1,9 @@
|
|||
from fastapi import FastAPI
|
||||
|
||||
from .routers import init_routers
|
||||
|
||||
|
||||
def app_factory() -> FastAPI:
|
||||
app = FastAPI()
|
||||
init_routers(app)
|
||||
return app
|
|
@ -0,0 +1,7 @@
|
|||
from fastapi import FastAPI
|
||||
|
||||
from api.presentation.routers import healthcheck_router
|
||||
|
||||
|
||||
def init_routers(app: FastAPI) -> None:
|
||||
app.include_router(healthcheck_router)
|
|
@ -0,0 +1,3 @@
|
|||
from .ping_response import PingResponse
|
||||
|
||||
__all__ = ("PingResponse",)
|
|
@ -2,6 +2,5 @@ from dataclasses import dataclass
|
|||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TokenDTO:
|
||||
access_token: str
|
||||
token_type: str
|
||||
class PingResponse:
|
||||
status: str
|
|
@ -1,47 +0,0 @@
|
|||
import os
|
||||
from dataclasses import dataclass
|
||||
from functools import lru_cache
|
||||
|
||||
import yaml # type: ignore
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DBSettings:
|
||||
pg_user: str
|
||||
pg_pass: str
|
||||
pg_host: str
|
||||
pg_port: int
|
||||
pg_db: str
|
||||
|
||||
@property
|
||||
def db_url(self) -> str:
|
||||
return "postgresql+asyncpg://{}:{}@{}:{}/{}".format(
|
||||
self.pg_user,
|
||||
self.pg_pass,
|
||||
self.pg_host,
|
||||
self.pg_port,
|
||||
self.pg_db,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RedisSettings:
|
||||
redis_host: str
|
||||
redis_port: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Settings:
|
||||
db: DBSettings
|
||||
redis: RedisSettings
|
||||
|
||||
|
||||
@lru_cache
|
||||
def get_settings():
|
||||
with open(os.getenv("CONFIG_PATH", "./config/api_config.yml")) as f:
|
||||
config_data: dict = yaml.safe_load(f)
|
||||
|
||||
return Settings(
|
||||
db=DBSettings(**config_data["db"]),
|
||||
redis=RedisSettings(**config_data["redis"]),
|
||||
)
|
|
@ -1,92 +0,0 @@
|
|||
from collections.abc import AsyncIterable, Callable
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.ext.asyncio import (
|
||||
AsyncEngine,
|
||||
AsyncSession,
|
||||
async_sessionmaker,
|
||||
create_async_engine,
|
||||
)
|
||||
|
||||
from api.config import get_settings
|
||||
|
||||
|
||||
class Stub:
|
||||
"""
|
||||
This class is used to prevent fastapi from digging into
|
||||
real dependencies attributes detecting them as request data
|
||||
|
||||
So instead of
|
||||
`interactor: Annotated[Interactor, Depends()]`
|
||||
Write
|
||||
`interactor: Annotated[Interactor, Depends(Stub(Interactor))]`
|
||||
|
||||
And then you can declare how to create it:
|
||||
`app.dependency_overrids[Interactor] = some_real_factory`
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, dependency: Callable, **kwargs):
|
||||
self._dependency = dependency
|
||||
self._kwargs = kwargs
|
||||
|
||||
def __call__(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if isinstance(other, Stub):
|
||||
return self._dependency == other._dependency and self._kwargs == other._kwargs
|
||||
else:
|
||||
if not self._kwargs:
|
||||
return self._dependency == other
|
||||
return False
|
||||
|
||||
def __hash__(self):
|
||||
if not self._kwargs:
|
||||
return hash(self._dependency)
|
||||
serial = (
|
||||
self._dependency,
|
||||
*self._kwargs.items(),
|
||||
)
|
||||
return hash(serial)
|
||||
|
||||
|
||||
# def new_user_repository(
|
||||
# session: Annotated[AsyncSession, Depends(Stub(AsyncSession))],
|
||||
# ) -> UserRepository:
|
||||
# return SqlalchemyUserRepository(session)
|
||||
#
|
||||
#
|
||||
# def new_unit_of_work(
|
||||
# session: Annotated[AsyncSession, Depends(Stub(AsyncSession))],
|
||||
# ) -> UnitOfWork:
|
||||
# return SqlalchemyUnitOfWork(session)
|
||||
#
|
||||
|
||||
|
||||
def create_engine() -> AsyncEngine:
|
||||
return create_async_engine(url=get_settings().db.db_url)
|
||||
|
||||
|
||||
def create_session_maker(
|
||||
engine: Annotated[AsyncEngine, Depends(Stub(AsyncEngine))],
|
||||
) -> async_sessionmaker[AsyncSession]:
|
||||
return async_sessionmaker(engine, expire_on_commit=False)
|
||||
|
||||
|
||||
async def new_session(
|
||||
session_maker: Annotated[
|
||||
async_sessionmaker[AsyncSession],
|
||||
Depends(Stub(async_sessionmaker[AsyncSession])),
|
||||
],
|
||||
) -> AsyncIterable[AsyncSession]:
|
||||
async with session_maker() as session:
|
||||
yield session
|
||||
|
||||
|
||||
# def new_user_service(
|
||||
# uow: Annotated[UnitOfWork, Depends()],
|
||||
# user_repository: Annotated[UserRepository, Depends()],
|
||||
# ) -> UserService:
|
||||
# return UserService(uow, user_repository)
|
|
@ -1,9 +0,0 @@
|
|||
from .base_model import BaseModel
|
||||
from .refers_model import RefersModel
|
||||
from .user_model import UserModel
|
||||
|
||||
__all__ = (
|
||||
"BaseModel",
|
||||
"UserModel",
|
||||
"RefersModel",
|
||||
)
|
|
@ -1,13 +0,0 @@
|
|||
import uuid
|
||||
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
|
||||
|
||||
|
||||
class BaseModel(DeclarativeBase):
|
||||
__abstract__ = True
|
||||
|
||||
id: Mapped[uuid.UUID] = mapped_column(
|
||||
UUID(as_uuid=True),
|
||||
primary_key=True,
|
||||
)
|
|
@ -1,18 +0,0 @@
|
|||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from api.models import BaseModel
|
||||
|
||||
|
||||
class RefersModel(BaseModel):
|
||||
__tablename__ = "refers"
|
||||
|
||||
referer: Mapped[UUID] = mapped_column(ForeignKey("user.id"))
|
||||
referals: Mapped[list["UserModel"]] = relationship(
|
||||
"UserModel",
|
||||
backref="refers",
|
||||
lazy="selectin",
|
||||
)
|
||||
is_active: Mapped[bool]
|
|
@ -1,11 +0,0 @@
|
|||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from api.models import BaseModel
|
||||
|
||||
|
||||
class UserModel(BaseModel):
|
||||
__tablename__ = "user"
|
||||
|
||||
name: Mapped[str]
|
||||
email: Mapped[str] = mapped_column(unique=True)
|
||||
hashed_password: Mapped[str]
|
|
@ -0,0 +1,3 @@
|
|||
from .ping import healthcheck_router
|
||||
|
||||
__all__ = ("healthcheck_router",)
|
|
@ -0,0 +1,13 @@
|
|||
from fastapi import APIRouter
|
||||
|
||||
from api.application.contracts.healht_check import PingResponse
|
||||
|
||||
healthcheck_router = APIRouter(
|
||||
prefix="/ping",
|
||||
tags=["HealthCheck"],
|
||||
)
|
||||
|
||||
|
||||
@healthcheck_router.get("/", status_code=200, response_model=PingResponse)
|
||||
async def ping_pong() -> PingResponse:
|
||||
return PingResponse(status="System OK")
|
|
@ -1,28 +0,0 @@
|
|||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class LifetimeRequestDTO:
|
||||
days: int = 0
|
||||
hours: int = 0
|
||||
minutes: int = 30
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ReferRequestDTO:
|
||||
lifetime: LifetimeRequestDTO
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RefererResponseDTO:
|
||||
name: str
|
||||
email: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ReferResponseDTO:
|
||||
refer_id: UUID
|
||||
expire_at: datetime
|
||||
referer: RefererResponseDTO
|
|
@ -1,16 +0,0 @@
|
|||
from dataclasses import dataclass
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UserRequestDTO:
|
||||
name: str
|
||||
email: str
|
||||
password: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UserResponseDTO:
|
||||
id: UUID
|
||||
name: str
|
||||
email: str
|
|
@ -1,3 +0,0 @@
|
|||
from .user import UserService
|
||||
|
||||
__all__ = ("UserService",)
|
|
@ -42,9 +42,9 @@ services:
|
|||
volumes:
|
||||
- ./config/api_config.yml:/usr/src/service_man/config/api_config.yml
|
||||
- ./api:/usr/src/service_man/api
|
||||
- ./alembic.ini:/usr/src/service_man/alembic.ini
|
||||
# - ./alembic.ini:/usr/src/service_man/alembic.ini
|
||||
|
||||
command: /bin/bash -c 'cd /usr/src/service_man && poetry run uvicorn api.app:create_app --host 0.0.0.0 --reload --factory'
|
||||
command: /bin/bash -c 'cd /usr/src/service_man && poetry run uvicorn api.app_builder.main:app_factory --host 0.0.0.0 --reload --factory'
|
||||
|
||||
# bot:
|
||||
# container_name: bot
|
||||
|
|
|
@ -2,7 +2,7 @@ if __name__ == "__main__":
|
|||
import uvicorn
|
||||
|
||||
uvicorn.run(
|
||||
app="api.app:create_app",
|
||||
app="api.app_builder.main:app_factory",
|
||||
host="0.0.0.0",
|
||||
port=8000,
|
||||
reload=True,
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
from fastapi import FastAPI
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
app = FastAPI()
|
||||
|
||||
return app
|
Loading…
Reference in New Issue