# Interface lives in the application/domain module from abc import ABC, abstractmethod from typing import Optional import httpx class BookingRepository(ABC): @abstractmethod async def find_by_id(self, booking_id: BookingId) -> Optional["Booking"]: pass @abstractmethod async def save(self, booking: "Booking") -> None: pass # Implementation lives in an infrastructure module class HttpBookingRepository(BookingRepository): def __init__(self, client: httpx.AsyncClient): self._client = client async def find_by_id(self, booking_id: BookingId) -> Optional["Booking"]: response = await self._client.get( f"https://api.example.com/bookings/{booking_id.value}" ) if response.status_code == 404: return None # Map HTTP/JSON → domain return Booking.from_dict(response.json()) async def save(self, booking: "Booking") -> None: await self._client.post( "https://api.example.com/bookings", json=booking.to_dict(), headers={"Content-Type": "application/json"}, )