Skip to content

Commit 8dda462

Browse files
benjaminpiliaBenjamin PILIAleoguillaume
authored
feat(refacto): update router endpoint toward clean architecture (#718)
* Refacto update router endpoint * Refacto router_repository et fixes * Revue Léo * fix(schemas): router schema * fix(schemas): alias typo * Update unit coverage badge --------- Co-authored-by: Benjamin PILIA <benjamin.pilia@protonmail.com> Co-authored-by: leoguillaume <leo.ch.guillaume@gmail.com> Co-authored-by: leoguillaume <leoguillaume@users.noreply.github.com>
1 parent a362dce commit 8dda462

File tree

14 files changed

+818
-163
lines changed

14 files changed

+818
-163
lines changed

.github/badges/coverage.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"schemaVersion":1,"label":"coverage","message":"50.59%","color":"red"}
1+
{"schemaVersion":1,"label":"coverage","message":"51.03%","color":"red"}

api/dependencies.py

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,21 @@
99
from api.infrastructure.postgres import PostgresKeyRepository, PostgresProviderRepository, PostgresRouterRepository, PostgresUserInfoRepository
1010
from api.schemas.core.context import RequestContext
1111
from api.use_cases.admin.providers import CreateProviderUseCase, DeleteProviderUseCase
12-
from api.use_cases.admin.routers import CreateRouterUseCase, DeleteRouterUseCase, GetOneRouterUseCase, GetRoutersUseCase
12+
from api.use_cases.admin.routers import CreateRouterUseCase, DeleteRouterUseCase, GetOneRouterUseCase, GetRoutersUseCase, UpdateRouterUseCase
1313
from api.use_cases.models import GetModelsUseCase
1414
from api.utils.configuration import configuration
1515
from api.utils.context import global_context, request_context
1616

1717

18+
def get_request_context() -> ContextVar[RequestContext]:
19+
return request_context
20+
21+
22+
def get_master_key() -> str:
23+
return configuration.settings.auth_master_key
24+
25+
26+
# databases
1827
async def get_postgres_session() -> AsyncGenerator[AsyncSession]:
1928
session_factory = global_context.postgres_session_factory
2029
async with session_factory() as postgres_session:
@@ -28,10 +37,7 @@ async def get_postgres_session() -> AsyncGenerator[AsyncSession]:
2837
raise
2938

3039

31-
def get_request_context() -> ContextVar[RequestContext]:
32-
return request_context
33-
34-
40+
# repositories
3541
def _router_repository(session: AsyncSession) -> PostgresRouterRepository:
3642
return PostgresRouterRepository(postgres_session=session, app_title=configuration.settings.app_title)
3743

@@ -40,6 +46,11 @@ def _user_info_repository(session: AsyncSession) -> PostgresUserInfoRepository:
4046
return PostgresUserInfoRepository(postgres_session=session)
4147

4248

49+
def get_key_repository(postgres_session: AsyncSession = Depends(get_postgres_session)) -> KeyRepository:
50+
return PostgresKeyRepository(postgres_session=postgres_session)
51+
52+
53+
# models use cases
4354
def get_models_use_case(
4455
postgres_session: AsyncSession = Depends(get_postgres_session),
4556
request_context: RequestContext = Depends(get_request_context),
@@ -51,45 +62,33 @@ def get_models_use_case(
5162
)
5263

5364

54-
def create_provider_use_case_factory(
55-
postgres_session: AsyncSession = Depends(get_postgres_session),
56-
) -> CreateProviderUseCase:
57-
return CreateProviderUseCase(
58-
router_repository=_router_repository(postgres_session),
59-
provider_repository=PostgresProviderRepository(postgres_session=postgres_session),
60-
provider_gateway=ModelProviderGateway(),
61-
user_info_repository=_user_info_repository(postgres_session),
62-
)
65+
# routers use cases
66+
def get_one_router_use_case_factory(postgres_session: AsyncSession = Depends(get_postgres_session)) -> GetOneRouterUseCase:
67+
return GetOneRouterUseCase(router_repository=_router_repository(postgres_session), user_info_repository=_user_info_repository(postgres_session))
6368

6469

65-
def get_one_router_use_case_factory(
66-
postgres_session: AsyncSession = Depends(get_postgres_session),
67-
) -> GetOneRouterUseCase:
68-
return GetOneRouterUseCase(
69-
router_repository=_router_repository(postgres_session),
70-
user_info_repository=_user_info_repository(postgres_session),
71-
)
72-
73-
74-
def get_routers_use_case_factory(
75-
postgres_session: AsyncSession = Depends(get_postgres_session),
76-
) -> GetRoutersUseCase:
77-
return GetRoutersUseCase(
78-
router_repository=_router_repository(postgres_session),
79-
user_info_repository=_user_info_repository(postgres_session),
80-
)
70+
def get_routers_use_case_factory(postgres_session: AsyncSession = Depends(get_postgres_session)) -> GetRoutersUseCase:
71+
return GetRoutersUseCase(router_repository=_router_repository(postgres_session), user_info_repository=_user_info_repository(postgres_session))
8172

8273

8374
def create_router_use_case_factory(postgres_session: AsyncSession = Depends(get_postgres_session)) -> CreateRouterUseCase:
84-
return CreateRouterUseCase(
85-
router_repository=_router_repository(postgres_session),
86-
user_info_repository=_user_info_repository(postgres_session),
87-
)
75+
return CreateRouterUseCase(router_repository=_router_repository(postgres_session), user_info_repository=_user_info_repository(postgres_session))
8876

8977

9078
def delete_router_use_case_factory(postgres_session: AsyncSession = Depends(get_postgres_session)) -> DeleteRouterUseCase:
91-
return DeleteRouterUseCase(
79+
return DeleteRouterUseCase(router_repository=_router_repository(postgres_session), user_info_repository=_user_info_repository(postgres_session))
80+
81+
82+
def update_router_use_case_factory(postgres_session: AsyncSession = Depends(get_postgres_session)) -> UpdateRouterUseCase:
83+
return UpdateRouterUseCase(router_repository=_router_repository(postgres_session), user_info_repository=_user_info_repository(postgres_session))
84+
85+
86+
# providers use cases
87+
def create_provider_use_case_factory(postgres_session: AsyncSession = Depends(get_postgres_session)) -> CreateProviderUseCase:
88+
return CreateProviderUseCase(
9289
router_repository=_router_repository(postgres_session),
90+
provider_repository=PostgresProviderRepository(postgres_session=postgres_session),
91+
provider_gateway=ModelProviderGateway(),
9392
user_info_repository=_user_info_repository(postgres_session),
9493
)
9594

@@ -99,11 +98,3 @@ def delete_provider_use_case_factory(postgres_session: AsyncSession = Depends(ge
9998
provider_repository=PostgresProviderRepository(postgres_session=postgres_session),
10099
user_info_repository=_user_info_repository(postgres_session),
101100
)
102-
103-
104-
def get_key_repository(postgres_session: AsyncSession = Depends(get_postgres_session)) -> KeyRepository:
105-
return PostgresKeyRepository(postgres_session=postgres_session)
106-
107-
108-
def get_master_key() -> str:
109-
return configuration.settings.auth_master_key

api/domain/router/_routerrepository.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,11 @@ async def create_router(
4848
@abstractmethod
4949
async def delete_router(self, router_id: int) -> Router | None:
5050
pass
51+
52+
@abstractmethod
53+
async def get_aliases(self, filtered_aliases: list[str] | None = None) -> list[str]:
54+
pass
55+
56+
@abstractmethod
57+
async def update_router(self, router_to_update: Router) -> Router | RouterNameAlreadyExistsError:
58+
pass

api/domain/router/entities.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
from dataclasses import dataclass
2-
from enum import Enum
2+
from enum import StrEnum
33

44
from pydantic import BaseModel, Field
55

66
from api.domain.model import ModelType as RouterType
77

88

9-
class RouterLoadBalancingStrategy(str, Enum):
9+
class RouterLoadBalancingStrategy(StrEnum):
1010
SHUFFLE = "shuffle"
1111
LEAST_BUSY = "least_busy"
1212

1313

14-
class RouterSortField(str, Enum):
14+
class RouterSortField(StrEnum):
1515
ID = "id"
1616
NAME = "name"
1717
CREATED = "created"
1818

1919

20-
class SortOrder(str, Enum):
20+
class SortOrder(StrEnum):
2121
ASC = "asc"
2222
DESC = "desc"
2323

@@ -42,3 +42,21 @@ class Router(BaseModel):
4242
providers: int = Field(default=0, description="Number of providers in the router.") # fmt: off
4343
created: int = Field(..., description="Time of creation, as Unix timestamp.") # fmt: off
4444
updated: int = Field(..., description="Time of last update, as Unix timestamp.") # fmt: off
45+
46+
def with_name(self, name: str) -> "Router":
47+
return self.model_copy(update={"name": name})
48+
49+
def with_type(self, router_type: RouterType) -> "Router":
50+
return self.model_copy(update={"type": router_type})
51+
52+
def with_load_balancing_strategy(self, strategy: RouterLoadBalancingStrategy) -> "Router":
53+
return self.model_copy(update={"load_balancing_strategy": strategy})
54+
55+
def with_cost_prompt_tokens(self, prompt_tokens: float) -> "Router":
56+
return self.model_copy(update={"cost_prompt_tokens": prompt_tokens})
57+
58+
def with_cost_completion_tokens(self, completion_tokens: float) -> "Router":
59+
return self.model_copy(update={"cost_completion_tokens": completion_tokens})
60+
61+
def with_aliases(self, aliases: list[str]) -> "Router":
62+
return self.model_copy(update={"aliases": aliases})

api/endpoints/admin/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
router = APIRouter(prefix="/v1", tags=[RouterName.ADMIN.title()])
66

7-
from . import organizations, providers, roles, routers, tokens, users # noqa: F401 E402
7+
from . import organizations, providers, roles, tokens, users # noqa: F401 E402

api/endpoints/admin/routers.py

Lines changed: 0 additions & 40 deletions
This file was deleted.

0 commit comments

Comments
 (0)