Skip to content

Commit 5b58e38

Browse files
authored
Merge pull request #34 from PacktPublishing/secured-api
initialize chapter8 secured api
2 parents 231f50e + 7d98ad8 commit 5b58e38

24 files changed

Lines changed: 1347 additions & 53 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,13 @@ jobs:
7373
run: uv run ruff check . --select "I,E,F,Q,UP,FAST" --line-length 120
7474

7575
- name: Run type checker
76-
run: uv run ty check || true
76+
run: uv run ty check
7777

7878
- name: Run pytest
7979
run: |
8080
# Check if tests directory or test files exist
81-
if [ -d "tests" ] || find . -name "test_*.py" -o -name "*_test.py" | grep -q .; then
81+
if [ -d "tests" ] || \
82+
find . -not -path "./.venv/*" \( -name "test_*.py" -o -name "*_test.py" \) | grep -q .; then
8283
uv run pytest -v
8384
else
8485
echo "No tests found in ${{ matrix.project }}"

Chapter07/sitters-catalog/config.py

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

3-
from pydantic import ConfigDict
4-
from pydantic_settings import BaseSettings
3+
from pydantic_settings import BaseSettings, SettingsConfigDict
54

65

76
class RepositoryType(StrEnum):
@@ -20,7 +19,7 @@ class Settings(BaseSettings):
2019
repository_type: RepositoryType = RepositoryType.TINYDB_FILE
2120
tinydb_path: str = "data/babysitters_db.json"
2221

23-
model_config = ConfigDict(env_file=".env")
22+
model_config = SettingsConfigDict(env_file=".env")
2423

2524

2625
settings = Settings()
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
from typing import Annotated
1+
from typing import Annotated, Any
22

33
from fastapi import APIRouter, Depends, status
44

55
from shared.dependencies import (
66
get_repository,
77
)
88
from shared.dto import BabysitterResponseDTO
9+
from shared.infrastructure import BaseRepository
910

1011
from .dto import CreateBabysitterDTO
1112
from .handler import create_babysitter
@@ -15,11 +16,11 @@
1516
)
1617

1718

18-
@router.post("/", status_code=status.HTTP_201_CREATED)
19+
@router.post("/", status_code=status.HTTP_201_CREATED, response_model=BabysitterResponseDTO)
1920
async def create_babysitter_endpoint(
2021
dto: CreateBabysitterDTO,
21-
repo: Annotated[object, Depends(get_repository)],
22-
) -> BabysitterResponseDTO:
22+
repo: Annotated[BaseRepository, Depends(get_repository)],
23+
) -> Any:
2324
"""Register a new babysitter in the catalog."""
2425
babysitter = await create_babysitter(dto, repo)
2526
return babysitter

Chapter07/sitters-catalog/features/deactivate_babysitter/route.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from typing import Annotated
1+
from typing import Annotated, Any
22

33
from fastapi import APIRouter, Depends, Path
44

55
from shared.dependencies import get_repository
66
from shared.dto import BabysitterResponseDTO
7+
from shared.infrastructure import BaseRepository
78

89
from .handler import deactivate_babysitter
910

@@ -17,10 +18,10 @@
1718
]
1819

1920

20-
@router.post("/{id}/deactivate")
21+
@router.post("/{id}/deactivate", response_model=BabysitterResponseDTO)
2122
async def deactivate_babysitter_endpoint(
2223
id: BabysitterIdDep,
23-
repo: Annotated[object, Depends(get_repository)],
24-
) -> BabysitterResponseDTO:
24+
repo: Annotated[BaseRepository, Depends(get_repository)],
25+
) -> Any:
2526
"""Soft-delete: set is_active=False, keep the record."""
2627
return await deactivate_babysitter(id, repo)

Chapter07/sitters-catalog/features/delete_babysitter/route.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from fastapi import APIRouter, Depends, Path, status
44

55
from shared.dependencies import get_repository
6+
from shared.infrastructure import BaseRepository
67

78
from .handler import delete_babysitter
89

@@ -19,7 +20,7 @@
1920
@router.delete("/{id}", status_code=status.HTTP_204_NO_CONTENT)
2021
async def delete_babysitter_endpoint(
2122
id: BabysitterIdDep,
22-
repo: Annotated[object, Depends(get_repository)],
23+
repo: Annotated[BaseRepository, Depends(get_repository)],
2324
) -> None:
2425
"""Permanently remove. Use /deactivate for soft-delete."""
2526
await delete_babysitter(id, repo)

Chapter07/sitters-catalog/features/get_babysitter/route.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from typing import Annotated
1+
from typing import Annotated, Any
22

33
from fastapi import APIRouter, Depends, Path
44

55
from shared.dependencies import get_repository
66
from shared.dto import BabysitterResponseDTO
7+
from shared.infrastructure import BaseRepository
78

89
from .handler import get_babysitter_by_id
910

@@ -17,10 +18,10 @@
1718
]
1819

1920

20-
@router.get("/{id}")
21+
@router.get("/{id}", response_model=BabysitterResponseDTO)
2122
async def get_babysitter_endpoint(
2223
id: BabysitterIdDep,
23-
repo: Annotated[object, Depends(get_repository)],
24-
) -> BabysitterResponseDTO:
24+
repo: Annotated[BaseRepository, Depends(get_repository)],
25+
) -> Any:
2526
"""Fetch a single babysitter by ID."""
2627
return await get_babysitter_by_id(id, repo)
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from typing import Annotated
1+
from typing import Annotated, Any
22

33
from fastapi import APIRouter, Depends
44

55
from shared.dependencies import get_repository
66
from shared.dto import BabysitterResponseDTO
7+
from shared.infrastructure import BaseRepository
78

89
from .handler import get_featured_babysitters
910

@@ -12,9 +13,9 @@
1213
)
1314

1415

15-
@router.get("/featured")
16+
@router.get("/featured", response_model=list[BabysitterResponseDTO])
1617
async def get_featured_endpoint(
17-
repo: Annotated[object, Depends(get_repository)],
18-
) -> list[BabysitterResponseDTO]:
18+
repo: Annotated[BaseRepository, Depends(get_repository)],
19+
) -> Any:
1920
"""Return the top 5 most experienced active babysitters."""
2021
return await get_featured_babysitters(repo)

Chapter07/sitters-catalog/features/list_babysitters/handler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from shared.dto import BabysitterResponseDTO
1+
from shared.domain.entities import Babysitter
22
from shared.infrastructure.base_repository import BaseRepository
33

44
from .dto import BabysitterSearchFilters
@@ -9,7 +9,7 @@ async def list_babysitters(
99
skip: int,
1010
limit: int,
1111
repo: BaseRepository,
12-
) -> list[BabysitterResponseDTO]:
12+
) -> list[Babysitter]:
1313
"""Search and list babysitters with optional filters."""
1414
raw: dict = {}
1515
if filters.city is not None:

Chapter07/sitters-catalog/features/list_babysitters/route.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
from typing import Annotated
1+
from typing import Annotated, Any
22

33
from fastapi import APIRouter, Depends, Query
44

55
from shared.dependencies import get_repository
66
from shared.dto import BabysitterResponseDTO
7+
from shared.infrastructure.base_repository import BaseRepository
78

89
from .dto import BabysitterSearchFilters
910
from .handler import list_babysitters
@@ -13,9 +14,9 @@
1314
)
1415

1516

16-
@router.get("/")
17+
@router.get("/", response_model=list[BabysitterResponseDTO])
1718
async def list_babysitters_endpoint(
18-
repo: Annotated[object, Depends(get_repository)],
19+
repo: Annotated[BaseRepository, Depends(get_repository)],
1920
city: Annotated[
2021
str | None, Query(description="Filter by city")
2122
] = None,
@@ -44,7 +45,7 @@ async def list_babysitters_endpoint(
4445
int,
4546
Query(ge=1, le=100, description="Page size (max 100)"),
4647
] = 20,
47-
) -> list[BabysitterResponseDTO]:
48+
) -> Any:
4849
"""Search and list babysitters with optional filters."""
4950
filters = BabysitterSearchFilters(
5051
city=city,

Chapter07/sitters-catalog/features/update_babysitter/route.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Annotated
1+
from typing import Annotated, Any
22

33
from fastapi import APIRouter, Depends, Path
44

@@ -19,21 +19,21 @@
1919
]
2020

2121

22-
@router.put("/{id}")
22+
@router.put("/{id}", response_model=BabysitterResponseDTO)
2323
async def update_babysitter_endpoint(
2424
id: BabysitterIdDep,
2525
dto: UpdateBabysitterDTO,
2626
repo: Annotated[BaseRepository, Depends(get_repository)],
27-
) -> BabysitterResponseDTO:
27+
) -> Any:
2828
"""Full update — replace all provided fields."""
2929
return await update_babysitter(id, dto, repo)
3030

3131

32-
@router.patch("/{id}")
32+
@router.patch("/{id}", response_model=BabysitterResponseDTO)
3333
async def partial_update_babysitter_endpoint(
3434
id: BabysitterIdDep,
3535
dto: UpdateBabysitterDTO,
3636
repo: Annotated[BaseRepository, Depends(get_repository)],
37-
) -> BabysitterResponseDTO:
37+
) -> Any:
3838
"""Partial update — only sent fields are changed."""
3939
return await update_babysitter(id, dto, repo)

0 commit comments

Comments
 (0)