feat: add FastAPI, Entity base class, and health check endpoint

This commit is contained in:
2026-07-29 10:38:16 -04:00
parent 2cb5045836
commit 5bb6cedd03
7 changed files with 123 additions and 23 deletions

View File

@@ -1,27 +1,18 @@
# Plan: UserId Value Object # Plan: Add FastAPI to the Project
## Status: COMPLETED ## Goal
Add FastAPI as the web framework with a minimal health check endpoint.
## Objective ## Changes
Create a UserId value object in the marketplace domain with an immutable UUID value.
## Decisions Made ### 1. Dependencies
- **Location**: `domain/marketplace/user_id.py` - Add `fastapi` and `uvicorn[standard]` to `pyproject.toml` under `[project.dependencies]`
- **Class style**: `@dataclass(frozen=True)` for immutability - Install dependencies into the virtual environment
- **Tests**: Yes
## Value Object Structure ### 2. Application Entry Point
```python - Create `main.py` with a FastAPI app instance
@dataclass(frozen=True) - Add a health check endpoint (`GET /`) that returns `{"status": "ok"}`
class UserId:
value: UUID
```
## Files Created ## Verification
- `domain/marketplace/user_id.py` - `pytest tests/` — all tests pass
- `tests/test_user_id.py` - `uvicorn main:app --reload` — server starts and health endpoint responds
## Test Results
- `test_user_id_creation` - PASSED
- `test_user_id_is_immutable` - PASSED
- `test_user_id_equality` - PASSED

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
env/ .venv/
__pycache__/ __pycache__/
*.pyc *.pyc
.pytest_cache/ .pytest_cache/

View File

View File

@@ -0,0 +1,18 @@
from abc import ABC
from dataclasses import replace
from typing import Self
from domain.marketplace.domain_event import DomainEvent
class Entity(ABC):
_events: tuple[DomainEvent, ...] = ()
def raise_event(self, event: DomainEvent) -> Self:
return replace(self, _events=(*self._events, event))
def get_changes(self) -> tuple[DomainEvent, ...]:
return self._events
def clear_changes(self) -> Self:
return replace(self, _events=())

8
main.py Normal file
View File

@@ -0,0 +1,8 @@
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def health_check():
return {"status": "ok"}

View File

@@ -6,6 +6,10 @@ build-backend = "setuptools.backends._legacy:_Backend"
name = "python-fun" name = "python-fun"
version = "0.1.0" version = "0.1.0"
requires-python = ">=3.12" requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115.0",
"uvicorn[standard]>=0.30.0",
]
[tool.pytest.ini_options] [tool.pytest.ini_options]
pythonpath = ["."] pythonpath = ["."]

79
tests/test_entity.py Normal file
View File

@@ -0,0 +1,79 @@
from dataclasses import dataclass
from uuid import uuid4
from domain.framework.entity import Entity
from domain.marketplace.domain_event import (
ClassifiedAdCreated,
ClassifiedAdSentForReview,
DomainEvent,
)
@dataclass(frozen=True)
class TestEntity(Entity):
__test__ = False
_events: tuple[DomainEvent, ...] = ()
def test_entity_creation():
entity = TestEntity()
assert entity.get_changes() == ()
def test_raise_event_returns_new_instance_with_event():
entity = TestEntity()
event = ClassifiedAdCreated(id=uuid4(), owner_id=uuid4())
new_entity = entity.raise_event(event)
assert new_entity.get_changes() == (event,)
def test_raise_event_does_not_mutate_original():
entity = TestEntity()
event = ClassifiedAdCreated(id=uuid4(), owner_id=uuid4())
entity.raise_event(event)
assert entity.get_changes() == ()
def test_multiple_events_accumulate():
entity = TestEntity()
event1 = ClassifiedAdCreated(id=uuid4(), owner_id=uuid4())
event2 = ClassifiedAdSentForReview(id=uuid4())
entity = entity.raise_event(event1)
entity = entity.raise_event(event2)
assert entity.get_changes() == (event1, event2)
def test_clear_changes_returns_instance_with_empty_events():
entity = TestEntity()
event = ClassifiedAdCreated(id=uuid4(), owner_id=uuid4())
entity = entity.raise_event(event)
cleared = entity.clear_changes()
assert cleared.get_changes() == ()
def test_clear_changes_does_not_mutate_original():
entity = TestEntity()
event = ClassifiedAdCreated(id=uuid4(), owner_id=uuid4())
entity = entity.raise_event(event)
entity.clear_changes()
assert entity.get_changes() == (event,)
def test_get_changes_returns_tuple():
entity = TestEntity()
event = ClassifiedAdCreated(id=uuid4(), owner_id=uuid4())
entity = entity.raise_event(event)
changes = entity.get_changes()
assert isinstance(changes, tuple)