add tests and docker infra

This commit is contained in:
ivankirpichnikov
2025-10-17 02:21:46 +03:00
parent 31d06fc0b4
commit 45d7926af1
24 changed files with 806 additions and 24 deletions
@@ -31,6 +31,10 @@ class ServerConfiguration:
port: int
access_log: bool
@property
def url(self) -> str:
return f"http://{self.host}:{self.port}"
@to_configuration
class Configuration:
@@ -1,5 +1,6 @@
import argparse
import asyncio
import os
import sys
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
@@ -14,6 +15,7 @@ from fastapi.middleware.cors import CORSMiddleware
from template_project.web_api.configuration import load_configuration
from template_project.web_api.ioc.make import make_ioc
from template_project.web_api.routes import healthcheck, user
LOG_CONFIG: Final = {
"version": 1,
@@ -53,15 +55,15 @@ def make_asgi_application(
version="1.0.0",
openapi_url="/openapi.json",
)
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(user.router)
app.include_router(healthcheck.router)
setup_dishka(container=ioc, app=app)
@@ -91,13 +93,17 @@ def main() -> None:
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
arg_parser = argparse.ArgumentParser()
subparsers = arg_parser.add_subparsers()
web_api_parser = subparsers.add_parser("web_api")
web_api_parser.add_argument("configuration", dest="configuration", type=Path)
arg_parser.add_argument("configuration", default=None)
args = arg_parser.parse_args()
_main(args.configuration)
configuration_path = args.configuration or os.getenv("CONFIGURATION_PATH")
if configuration_path is None:
raise RuntimeError(
"pass the path to the config or specify it in the environment variables `CONFIGURATION_PATH`",
)
_main(Path(configuration_path))
if __name__ == "__main__":
@@ -8,13 +8,13 @@ from template_project.web_api.configuration import DatabaseConfiguration
class ConnectionProvider(Provider):
@provide(scope=Scope.APP)
async def make_engine(self, configuration: DatabaseConfiguration) -> AsyncIterable[AsyncEngine]:
async def engine(self, configuration: DatabaseConfiguration) -> AsyncIterable[AsyncEngine]:
engine = create_async_engine(configuration.url.get_value())
yield engine
await engine.dispose()
@provide()
async def make_connection(self, engine: AsyncEngine) -> AsyncIterable[AsyncSession]:
@provide(scope=Scope.REQUEST)
async def async_session(self, engine: AsyncEngine) -> AsyncIterable[AsyncSession]:
session = AsyncSession(
bind=engine,
expire_on_commit=True,
+9
View File
@@ -0,0 +1,9 @@
from dishka import BaseScope, Provider, Scope, provide
from template_project.web_api.identity_provider import WebApiIdentityProvider
class IdPProvider(Provider):
scope: BaseScope | None = Scope.REQUEST
web_api = provide(WebApiIdentityProvider)
+6 -1
View File
@@ -1,4 +1,4 @@
from dishka import AsyncContainer, make_async_container
from dishka import STRICT_VALIDATION, AsyncContainer, make_async_container
from dishka.integrations.fastapi import FastapiProvider
from template_project.web_api.configuration import (
@@ -7,19 +7,24 @@ from template_project.web_api.configuration import (
DatabaseConfiguration,
ServerConfiguration,
)
from template_project.web_api.ioc.connection import ConnectionProvider
from template_project.web_api.ioc.cryptographer import CryptographerProvider
from template_project.web_api.ioc.data_gateway import DataGatewayProvider
from template_project.web_api.ioc.factory import FactoryProvider
from template_project.web_api.ioc.idp import IdPProvider
from template_project.web_api.ioc.interactor import InteractorProvider
def make_ioc(configuration: Configuration) -> AsyncContainer:
return make_async_container(
IdPProvider(),
FactoryProvider(),
FastapiProvider(),
ConnectionProvider(),
InteractorProvider(),
DataGatewayProvider(),
CryptographerProvider(),
validation_settings=STRICT_VALIDATION,
context={
ServerConfiguration: configuration.server,
DatabaseConfiguration: configuration.database,
@@ -0,0 +1,14 @@
from dishka.integrations.fastapi import DishkaRoute
from fastapi import APIRouter
from pydantic import BaseModel
router = APIRouter(route_class=DishkaRoute)
class HealthcheckResponse(BaseModel):
ok: bool
@router.get("/healthcheck")
async def healthcheck() -> HealthcheckResponse:
return HealthcheckResponse(ok=True)