diff --git a/app/api/decks.py b/app/api/decks.py index 881947b..eda9b88 100644 --- a/app/api/decks.py +++ b/app/api/decks.py @@ -1,9 +1,7 @@ import typing import fastapi -from advanced_alchemy.exceptions import NotFoundError from modern_di_fastapi import FromDI -from starlette import status from app import models, schemas from app.repositories import CardsRepository, DecksRepository @@ -26,9 +24,6 @@ async def get_deck( decks_repository: DecksRepository = FromDI(DecksRepository), ) -> schemas.Deck: instance = await decks_repository.fetch_with_cards(deck_id) - if not instance: - raise fastapi.HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Deck is not found") - return typing.cast("schemas.Deck", instance) @@ -38,11 +33,7 @@ async def update_deck( data: schemas.DeckCreate, decks_repository: DecksRepository = FromDI(DecksRepository), ) -> schemas.Deck: - try: - instance = await decks_repository.update(data=data.model_dump(), item_id=deck_id) - except NotFoundError: - raise fastapi.HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Deck is not found") from None - + instance = await decks_repository.update(data=data.model_dump(), item_id=deck_id) return typing.cast("schemas.Deck", instance) @@ -69,9 +60,7 @@ async def get_card( card_id: int, cards_repository: CardsRepository = FromDI(CardsRepository), ) -> schemas.Card: - instance = await cards_repository.get_one_or_none(models.Card.id == card_id) - if not instance: - raise fastapi.HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Card is not found") + instance = await cards_repository.get_one(models.Card.id == card_id) return typing.cast("schemas.Card", instance) diff --git a/app/application.py b/app/application.py index d26aa25..56e7f0e 100644 --- a/app/application.py +++ b/app/application.py @@ -3,7 +3,7 @@ import modern_di import modern_di_fastapi -from advanced_alchemy.exceptions import DuplicateKeyError +from advanced_alchemy.exceptions import DuplicateKeyError, NotFoundError from lite_bootstrap import FastAPIBootstrapper from opentelemetry.instrumentation.asyncpg import AsyncPGInstrumentor from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor @@ -38,4 +38,8 @@ def build_app() -> fastapi.FastAPI: DuplicateKeyError, exceptions.duplicate_key_error_handler, # ty: ignore[invalid-argument-type] ) + app.add_exception_handler( + NotFoundError, + exceptions.not_found_error_handler, # ty: ignore[invalid-argument-type] + ) return app diff --git a/app/exceptions.py b/app/exceptions.py index 1ff5e02..11a7bed 100644 --- a/app/exceptions.py +++ b/app/exceptions.py @@ -5,7 +5,7 @@ if TYPE_CHECKING: - from advanced_alchemy.exceptions import DuplicateKeyError + from advanced_alchemy.exceptions import DuplicateKeyError, NotFoundError from starlette.requests import Request @@ -14,3 +14,10 @@ async def duplicate_key_error_handler(_: Request, exc: DuplicateKeyError) -> JSO status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, content={"detail": exc.detail}, ) + + +async def not_found_error_handler(_: Request, __: NotFoundError) -> JSONResponse: + return JSONResponse( + status_code=status.HTTP_404_NOT_FOUND, + content={"detail": "Not found"}, + ) diff --git a/app/repositories.py b/app/repositories.py index 3c0d608..af6b577 100644 --- a/app/repositories.py +++ b/app/repositories.py @@ -17,8 +17,8 @@ class BaseRepository(SQLAlchemyAsyncRepository[models.Deck]): repository_type = BaseRepository - async def fetch_with_cards(self, deck_id: int) -> models.Deck | None: - return await self.get_one_or_none( + async def fetch_with_cards(self, deck_id: int) -> models.Deck: + return await self.get_one( models.Deck.id == deck_id, load=[orm.selectinload(models.Deck.cards)], )