Skip to content

Commit de8e330

Browse files
committed
replace seedwork Application with lato Application
1 parent 53b7041 commit de8e330

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1527
-671
lines changed

.python-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.10.0
1+
3.11

diary.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def get_route_controller(request, module):
2929
3030
3131
def post_route_controller(request, module):
32-
result = module.execute_command(MyCommand(
32+
result = module.execute(MyCommand(
3333
foo=request.POST.foo,
3434
bar=request.POST.bar,
3535
))

docs/architecture_decision_log/005_separate_commands_and_queries.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def get_route_controller(request, module):
2020
2121
2222
def post_route_controller(request, module):
23-
result = module.execute_command(MyCommand(
23+
result = module.execute(MyCommand(
2424
foo=request.POST.foo,
2525
bar=request.POST.bar,
2626
))

poetry.lock

+1,183-385
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ authors = ["Przemysław Górecki <[email protected]>"]
66

77
[tool.poetry.dependencies]
88
python = "^3.10.0"
9-
pytest = "^6.2.4"
10-
pydantic = "^1.8.2"
119
black = "^21.5b1"
12-
fastapi = "^0.95.2"
1310
uvicorn = "^0.14.0"
1411
starlette-context = "^0.3.3"
1512
SQLAlchemy = "^1.4.22"
@@ -29,6 +26,9 @@ httpx = "^0.23.1"
2926
requests = "^2.28.1"
3027
bcrypt = "^4.0.1"
3128
mypy = "^1.4.1"
29+
fastapi = "^0.110.0"
30+
lato = "^0.10.0"
31+
pydantic-settings = "^2.2.1"
3232

3333
[tool.poetry.dev-dependencies]
3434
poethepoet = "^0.10.0"

src/api/dependencies.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from modules.iam.application.services import IamService
77
from modules.iam.domain.entities import User
8-
from seedwork.application import Application, TransactionContext
8+
from lato import Application, TransactionContext
99

1010
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
1111

@@ -28,5 +28,5 @@ async def get_authenticated_user(
2828
access_token: Annotated[str, Depends(oauth2_scheme)],
2929
ctx: Annotated[TransactionContext, Depends(get_transaction_context)],
3030
) -> User:
31-
current_user = ctx.get_service(IamService).find_user_by_access_token(access_token)
31+
current_user = ctx[IamService].find_user_by_access_token(access_token)
3232
return current_user

src/api/main.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from api.dependencies import oauth2_scheme # noqa
77
from api.routers import bidding, catalog, diagnostics, iam
88
from config.api_config import ApiConfig
9-
from config.container import TopLevelContainer
9+
from config.container import create_application, ApplicationContainer
1010
from seedwork.domain.exceptions import DomainException, EntityNotFoundException
1111
from seedwork.infrastructure.database import Base
1212
from seedwork.infrastructure.logging import LoggerFactory, logger
@@ -15,29 +15,30 @@
1515
LoggerFactory.configure(logger_name="api")
1616

1717
# dependency injection container
18-
container = TopLevelContainer()
19-
container.config.from_pydantic(ApiConfig())
18+
config = ApiConfig()
19+
container = ApplicationContainer(config=config)
20+
db_engine = container.db_engine()
21+
logger.info(f"using db engine {db_engine}, creating tables")
22+
Base.metadata.create_all(db_engine)
23+
logger.info("setup complete")
2024

21-
app = FastAPI(debug=container.config.DEBUG)
25+
app = FastAPI(debug=config.DEBUG)
2226

2327
app.include_router(catalog.router)
2428
app.include_router(bidding.router)
2529
app.include_router(iam.router)
2630
app.include_router(diagnostics.router)
2731
app.container = container
2832

29-
db_engine = container.db_engine()
30-
logger.info(f"using db engine {db_engine}, creating tables")
31-
Base.metadata.create_all(db_engine)
32-
logger.info("setup complete")
33+
3334

3435
try:
3536
import uuid
3637

3738
from modules.iam.application.services import IamService
3839

3940
with app.container.application().transaction_context() as ctx:
40-
iam_service = ctx.get_service(IamService)
41+
iam_service = ctx[IamService]
4142
iam_service.create_user(
4243
user_id=uuid.UUID(int=1),
4344

src/api/models/bidding.py

+9
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,24 @@ class BidReadModel(BaseModel):
1010
currency: str
1111
bidder_id: GenericUUID
1212
bidder_username: str
13+
14+
class Config:
15+
arbitrary_types_allowed = True
1316

1417

1518
class BiddingResponse(BaseModel):
1619
listing_id: GenericUUID
1720
auction_status: str = "active" # active, ended
1821
auction_end_date: datetime
1922
bids: list[BidReadModel]
23+
24+
class Config:
25+
arbitrary_types_allowed = True
2026

2127

2228
class PlaceBidRequest(BaseModel):
2329
bidder_id: GenericUUID
2430
amount: float
31+
32+
class Config:
33+
arbitrary_types_allowed = True

src/api/routers/bidding.py

+11-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from config.container import inject
88
from modules.bidding.application.command import PlaceBidCommand, RetractBidCommand
99
from modules.bidding.application.query.get_bidding_details import GetBiddingDetails
10-
from seedwork.application import Application
10+
from lato import Application
1111

1212
router = APIRouter()
1313

@@ -25,12 +25,11 @@ async def get_bidding_details_of_listing(
2525
Shows listing details
2626
"""
2727
query = GetBiddingDetails(listing_id=listing_id)
28-
query_result = app.execute_query(query)
29-
payload = query_result.payload
28+
result = app.execute(query)
3029
return BiddingResponse(
31-
listing_id=str(payload.id),
32-
auction_end_date=payload.ends_at,
33-
bids=payload.bids,
30+
listing_id=result.id,
31+
auction_end_date=result.ends_at,
32+
bids=result.bids,
3433
)
3534

3635

@@ -53,15 +52,14 @@ async def place_bid(
5352
bidder_id=request_body.bidder_id,
5453
amount=request_body.amount,
5554
)
56-
result = app.execute_command(command)
55+
app.execute(command)
5756

5857
query = GetBiddingDetails(listing_id=listing_id)
59-
query_result = app.execute_query(query)
60-
payload = query_result.payload
58+
result = app.execute(query)
6159
return BiddingResponse(
62-
listing_id=str(payload.id),
63-
auction_end_date=payload.ends_at,
64-
bids=payload.bids,
60+
listing_id=result.id,
61+
auction_end_date=result.ends_at,
62+
bids=result.bids,
6563
)
6664

6765

@@ -81,7 +79,7 @@ async def retract_bid(
8179
listing_id=listing_id,
8280
bidder_id="",
8381
)
84-
app.execute_command(command)
82+
app.execute(command)
8583

8684
query = GetBiddingDetails(listing_id=listing_id)
8785
query_result = app.execute_query(query)

src/api/routers/catalog.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323

2424
@router.get("/catalog", tags=["catalog"], response_model=ListingIndexModel)
2525
@inject
26-
async def get_all_listings(app: Annotated[Application, Depends(get_application)]):
26+
def get_all_listings(app: Annotated[Application, Depends(get_application)]):
2727
"""
2828
Shows all published listings in the catalog
2929
"""
3030
query = GetAllListings()
31-
query_result = app.execute_query(query)
32-
return dict(data=query_result.payload)
31+
result = app.execute(query)
32+
return dict(data=result)
3333

3434

3535
@router.get("/catalog/{listing_id}", tags=["catalog"], response_model=ListingReadModel)
@@ -64,7 +64,7 @@ async def create_listing(
6464
ask_price=Money(request_body.ask_price_amount, request_body.ask_price_currency),
6565
seller_id=current_user.id,
6666
)
67-
app.execute_command(command)
67+
app.execute(command)
6868

6969
query = GetListingDetails(listing_id=command.listing_id)
7070
query_result = app.execute_query(query)
@@ -87,7 +87,7 @@ async def delete_listing(
8787
listing_id=listing_id,
8888
seller_id=current_user.id,
8989
)
90-
app.execute_command(command)
90+
app.execute(command)
9191

9292

9393
@router.post(
@@ -109,8 +109,8 @@ async def publish_listing(
109109
listing_id=listing_id,
110110
seller_id=current_user.id,
111111
)
112-
app.execute_command(command)
112+
app.execute(command)
113113

114114
query = GetListingDetails(listing_id=listing_id)
115-
query_result = app.execute_query(query)
116-
return dict(query_result.payload)
115+
response = app.execute(query)
116+
return response

src/api/routers/diagnostics.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from fastapi import APIRouter, Depends
44

55
from api.dependencies import (
6-
TransactionContext,
6+
Application,
77
User,
88
get_authenticated_user,
9-
get_transaction_context,
9+
get_application,
1010
)
1111

1212
from .iam import UserResponse
@@ -16,13 +16,13 @@
1616

1717
@router.get("/debug", tags=["diagnostics"])
1818
async def debug(
19-
ctx: Annotated[TransactionContext, Depends(get_transaction_context)],
19+
app: Annotated[Application, Depends(get_application)],
2020
current_user: Annotated[User, Depends(get_authenticated_user)],
2121
):
2222
return dict(
23-
app_id=id(ctx.app),
24-
name=ctx.app.name,
25-
version=ctx.app.version,
23+
app_id=id(app),
24+
name=app.name,
25+
version=app["app_version"],
2626
user=UserResponse(
2727
id=str(current_user.id),
2828
username=current_user.username,

src/api/routers/iam.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ async def login(
3636
form_data: OAuth2PasswordRequestForm = Depends(),
3737
) -> LoginResponse:
3838
try:
39-
iam_service = ctx.get_service(IamService)
39+
iam_service = ctx[IamService]
4040
user = iam_service.authenticate_with_name_and_password(
4141
form_data.username, form_data.password
4242
)

src/api/tests/test_bidding.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
def setup_app_for_bidding_tests(app, listing_id, seller_id, bidder_id):
1212
logger.info("Adding users")
1313
with app.transaction_context() as ctx:
14-
iam_service = ctx.dependency_provider["iam_service"]
14+
iam_service = ctx["iam_service"]
1515

1616
iam_service.create_user(
1717
user_id=seller_id,
@@ -27,7 +27,7 @@ def setup_app_for_bidding_tests(app, listing_id, seller_id, bidder_id):
2727
)
2828

2929
logger.info("Adding listing")
30-
app.execute_command(
30+
app.execute(
3131
CreateListingDraftCommand(
3232
listing_id=listing_id,
3333
title="Foo",
@@ -36,7 +36,7 @@ def setup_app_for_bidding_tests(app, listing_id, seller_id, bidder_id):
3636
seller_id=seller_id,
3737
)
3838
)
39-
app.execute_command(
39+
app.execute(
4040
PublishListingDraftCommand(listing_id=listing_id, seller_id=seller_id)
4141
)
4242
logger.info("test setup complete")
@@ -52,4 +52,5 @@ def test_place_bid(app, api_client):
5252
url = f"/bidding/{listing_id}/place_bid"
5353

5454
response = api_client.post(url, json={"bidder_id": str(bidder_id), "amount": 11})
55+
json = response.json()
5556
assert response.status_code == 200

src/api/tests/test_catalog.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def test_empty_catalog_list(api_client):
1717
@pytest.mark.integration
1818
def test_catalog_list_with_one_item(app, api_client):
1919
# arrange
20-
app.execute_command(
20+
app.execute(
2121
CreateListingDraftCommand(
2222
listing_id=GenericUUID(int=1),
2323
title="Foo",
@@ -50,7 +50,7 @@ def test_catalog_list_with_one_item(app, api_client):
5050
@pytest.mark.integration
5151
def test_catalog_list_with_two_items(app, api_client):
5252
# arrange
53-
app.execute_command(
53+
app.execute(
5454
CreateListingDraftCommand(
5555
listing_id=GenericUUID(int=1),
5656
title="Foo #1",
@@ -59,7 +59,7 @@ def test_catalog_list_with_two_items(app, api_client):
5959
seller_id=GenericUUID(int=2),
6060
)
6161
)
62-
app.execute_command(
62+
app.execute(
6363
CreateListingDraftCommand(
6464
listing_id=GenericUUID(int=2),
6565
title="Foo #2",
@@ -88,7 +88,7 @@ def test_catalog_create_draft_fails_due_to_incomplete_data(
8888
@pytest.mark.integration
8989
def test_catalog_delete_draft(app, authenticated_api_client):
9090
current_user = authenticated_api_client.current_user
91-
app.execute_command(
91+
app.execute(
9292
CreateListingDraftCommand(
9393
listing_id=GenericUUID(int=1),
9494
title="Listing to be deleted",
@@ -115,7 +115,7 @@ def test_catalog_publish_listing_draft(app, authenticated_api_client):
115115
# arrange
116116
current_user = authenticated_api_client.current_user
117117
listing_id = GenericUUID(int=1)
118-
app.execute_command(
118+
app.execute(
119119
CreateListingDraftCommand(
120120
listing_id=listing_id,
121121
title="Listing to be published",
@@ -136,7 +136,7 @@ def test_published_listing_appears_in_biddings(app, authenticated_api_client):
136136
# arrange
137137
listing_id = GenericUUID(int=1)
138138
current_user = authenticated_api_client.current_user
139-
app.execute_command(
139+
app.execute(
140140
CreateListingDraftCommand(
141141
listing_id=listing_id,
142142
title="Listing to be published",
@@ -145,7 +145,7 @@ def test_published_listing_appears_in_biddings(app, authenticated_api_client):
145145
seller_id=current_user.id,
146146
)
147147
)
148-
app.execute_command(
148+
app.execute(
149149
PublishListingDraftCommand(
150150
listing_id=listing_id,
151151
seller_id=current_user.id,

src/api/tests/test_login.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
def test_login_with_api_token(app, api_client):
99
# arrange
1010
with app.transaction_context() as ctx:
11-
iam_service = ctx.get_service(IamService)
11+
iam_service = ctx[IamService]
1212
iam_service.create_user(
1313
user_id=GenericUUID(int=1),
1414
@@ -31,7 +31,7 @@ def test_login_with_api_token(app, api_client):
3131
def test_login_with_invalid_username_returns_400(app, api_client):
3232
# arrange
3333
with app.transaction_context() as ctx:
34-
iam_service = ctx.get_service(IamService)
34+
iam_service = ctx[IamService]
3535
iam_service.create_user(
3636
user_id=GenericUUID(int=1),
3737
@@ -53,7 +53,7 @@ def test_login_with_invalid_username_returns_400(app, api_client):
5353
def test_login_with_invalid_password_returns_400(app, api_client):
5454
# arrange
5555
with app.transaction_context() as ctx:
56-
iam_service = ctx.get_service(IamService)
56+
iam_service = ctx[IamService]
5757
iam_service.create_user(
5858
user_id=GenericUUID(int=1),
5959

0 commit comments

Comments
 (0)