Skip to content

Commit 32da6b0

Browse files
committed
Extract 404 error from service layer
1 parent f6a64c6 commit 32da6b0

File tree

14 files changed

+38
-54
lines changed

14 files changed

+38
-54
lines changed

futuramaapi/apps/fastapi.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,21 @@ def _setup_static(self) -> None:
9999
)
100100

101101
def _exception_handler(self, _: Request, exc) -> Response:
102-
from futuramaapi.routers.services import ServiceError, UnauthorizedError # noqa: PLC0415
102+
from futuramaapi.routers.services import ( # noqa: PLC0415
103+
NotFoundError,
104+
ServiceError,
105+
UnauthorizedError,
106+
)
103107

104108
exception_to_value: dict[type[ServiceError], _ExceptionValue] = {
105109
UnauthorizedError: _ExceptionValue(
106110
status_code=status.HTTP_401_UNAUTHORIZED,
107111
default_message="Unauthorized",
108112
),
113+
NotFoundError: _ExceptionValue(
114+
status_code=status.HTTP_404_NOT_FOUND,
115+
default_message="Not Found",
116+
),
109117
}
110118

111119
exc_value = exception_to_value[type(exc)]

futuramaapi/routers/services/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
BaseService,
33
BaseSessionService,
44
BaseUserAuthenticatedService,
5+
NotFoundError,
56
ServiceError,
67
UnauthorizedError,
78
)
@@ -12,6 +13,7 @@
1213
"BaseSessionService",
1314
"BaseTemplateService",
1415
"BaseUserAuthenticatedService",
16+
"NotFoundError",
1517
"ServiceError",
1618
"UnauthorizedError",
1719
]

futuramaapi/routers/services/_base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class UnauthorizedError(ServiceError):
2828
"""Unauthorized Error."""
2929

3030

31+
class NotFoundError(ServiceError):
32+
"""Not Found Error."""
33+
34+
3135
class BaseService[TResponse](BaseModel, ABC):
3236
context: dict[str, Any] | None = None
3337

futuramaapi/routers/services/characters/get_character.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from datetime import datetime
22

3-
from fastapi import HTTPException, status
43
from fastapi_storages import StorageImage
54
from pydantic import HttpUrl, field_validator
65
from sqlalchemy import Select, select
@@ -9,7 +8,7 @@
98
from futuramaapi.core import settings
109
from futuramaapi.helpers.pydantic import BaseModel
1110
from futuramaapi.repositories.models import CharacterModel
12-
from futuramaapi.routers.services import BaseSessionService
11+
from futuramaapi.routers.services import BaseSessionService, NotFoundError
1312

1413

1514
class GetCharacterResponse(BaseModel):
@@ -42,6 +41,6 @@ async def process(self, *args, **kwargs) -> GetCharacterResponse:
4241
try:
4342
result: CharacterModel = (await self.session.execute(self.statement)).scalars().one()
4443
except NoResultFound:
45-
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Character not found") from None
44+
raise NotFoundError("Character not found") from None
4645

4746
return GetCharacterResponse.model_validate(result)

futuramaapi/routers/services/crypto/get_secret_message.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22
from dataclasses import dataclass
33
from typing import ClassVar
44

5-
from fastapi import HTTPException, Request, status
5+
from fastapi import Request
66
from pydantic import field_serializer
77
from sqlalchemy import Row, RowMapping, Select, case, select, update
88
from sqlalchemy.exc import NoResultFound
99

1010
from futuramaapi.helpers.pydantic import BaseModel
1111
from futuramaapi.repositories.models import SecretMessageModel
12-
from futuramaapi.routers.services import BaseSessionService
12+
from futuramaapi.routers.services import BaseSessionService, NotFoundError
1313

1414

1515
class GetSecretMessageResponse(BaseModel):
@@ -316,10 +316,7 @@ async def process(
316316
try:
317317
row: Row[tuple[SecretMessageRow]] = (await self.session.execute(self._get_statement(request))).one()
318318
except NoResultFound:
319-
raise HTTPException(
320-
status_code=status.HTTP_404_NOT_FOUND,
321-
detail="Not Found",
322-
) from None
319+
raise NotFoundError() from None
323320

324321
await self.session.commit()
325322

futuramaapi/routers/services/episodes/get_episode.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
from datetime import date, datetime
22

3-
from fastapi import HTTPException, status
43
from pydantic import Field, computed_field
54
from sqlalchemy import Select, select
65
from sqlalchemy.exc import NoResultFound
76
from sqlalchemy.orm import selectinload
87

98
from futuramaapi.helpers.pydantic import BaseModel
109
from futuramaapi.repositories.models import EpisodeModel
11-
from futuramaapi.routers.services import BaseSessionService
10+
from futuramaapi.routers.services import BaseSessionService, NotFoundError
1211

1312

1413
class GetEpisodeResponse(BaseModel):
@@ -53,9 +52,6 @@ async def process(self, *args, **kwargs) -> GetEpisodeResponse:
5352
try:
5453
season_model: EpisodeModel = (await self.session.execute(self.statement)).scalars().one()
5554
except NoResultFound:
56-
raise HTTPException(
57-
detail="Episode not found",
58-
status_code=status.HTTP_404_NOT_FOUND,
59-
) from None
55+
raise NotFoundError("Episode not found") from None
6056

6157
return GetEpisodeResponse.model_validate(season_model)

futuramaapi/routers/services/favorites/create_favorite_character.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from sqlalchemy.exc import IntegrityError
55

66
from futuramaapi.repositories.models import CharacterModel, FavoriteCharacterModel
7-
from futuramaapi.routers.services import BaseUserAuthenticatedService
7+
from futuramaapi.routers.services import BaseUserAuthenticatedService, NotFoundError
88

99

1010
class CreateFavoriteCharacterService(BaseUserAuthenticatedService[None]):
@@ -33,9 +33,6 @@ async def process(self) -> None:
3333
raise
3434

3535
if result.rowcount == 0:
36-
raise HTTPException(
37-
status_code=status.HTTP_404_NOT_FOUND,
38-
detail="Character not found",
39-
)
36+
raise NotFoundError("Character not found")
4037

4138
await self.session.commit()

futuramaapi/routers/services/favorites/delete_favorite_character.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
from fastapi import HTTPException, status
21
from sqlalchemy import Delete, Result, delete, select
32

43
from futuramaapi.repositories.models import CharacterModel, FavoriteCharacterModel
5-
from futuramaapi.routers.services import BaseUserAuthenticatedService
4+
from futuramaapi.routers.services import BaseUserAuthenticatedService, NotFoundError
65

76

87
class DeleteFavoriteCharacterService(BaseUserAuthenticatedService[None]):
@@ -19,9 +18,6 @@ def _statement(self) -> Delete[tuple[FavoriteCharacterModel, CharacterModel]]:
1918
async def process(self, *args, **kwargs) -> None:
2019
result: Result[tuple[FavoriteCharacterModel]] = await self.session.execute(self._statement)
2120
if result.rowcount == 0:
22-
raise HTTPException(
23-
status_code=status.HTTP_404_NOT_FOUND,
24-
detail="Character not found or not in favorites",
25-
)
21+
raise NotFoundError("Character not found or not in favorites")
2622

2723
await self.session.commit()

futuramaapi/routers/services/links/get_link.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
from datetime import datetime
22
from typing import ClassVar
33

4-
from fastapi import HTTPException, status
54
from pydantic import Field, HttpUrl, computed_field
65
from sqlalchemy import Result, Select, select
76
from sqlalchemy.exc import NoResultFound
87

98
from futuramaapi.core import settings
109
from futuramaapi.helpers.pydantic import BaseModel
1110
from futuramaapi.repositories.models import LinkModel
12-
from futuramaapi.routers.services import BaseUserAuthenticatedService
11+
from futuramaapi.routers.services import BaseUserAuthenticatedService, NotFoundError
1312

1413

1514
class GetLinkResponse(BaseModel):
@@ -52,9 +51,6 @@ async def process(self, *args, **kwargs) -> GetLinkResponse:
5251
try:
5352
link: LinkModel = result.scalars().one()
5453
except NoResultFound:
55-
raise HTTPException(
56-
status_code=status.HTTP_404_NOT_FOUND,
57-
detail="Link not found.",
58-
) from None
54+
raise NotFoundError("Link not found") from None
5955

6056
return GetLinkResponse.model_validate(link)

futuramaapi/routers/services/links/redirect_link.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
from fastapi import HTTPException, status
21
from fastapi.responses import RedirectResponse
32
from sqlalchemy import Result, Select, select
43
from sqlalchemy.exc import NoResultFound
54

65
from futuramaapi.repositories.models import LinkModel
7-
from futuramaapi.routers.services import BaseSessionService
6+
from futuramaapi.routers.services import BaseSessionService, NotFoundError
87

98

109
class RedirectLinkService(BaseSessionService[RedirectResponse]):
@@ -19,10 +18,7 @@ async def process(self, *args, **kwargs) -> RedirectResponse:
1918
try:
2019
link: LinkModel = result.scalars().one()
2120
except NoResultFound:
22-
raise HTTPException(
23-
status_code=status.HTTP_404_NOT_FOUND,
24-
detail="Link not found.",
25-
) from None
21+
raise NotFoundError("Link not found") from None
2622

2723
link.counter += 1
2824
await self.session.commit()

0 commit comments

Comments
 (0)