Skip to main content

Overview

Domain interfaces define the contracts that infrastructure implementations must fulfill. They enable dependency inversion and loose coupling between layers.

ScraperInterface

Base interface for movie scrapers.

Class Definition

from abc import ABC, abstractmethod
from typing import List
from domain.models.movie import Movie

class ScraperInterface(ABC):
    @abstractmethod
    def scrape(self) -> List[Movie]:
        pass
Source: domain/interfaces/scraper_interface.py:5-21

Methods

scrape

Executes the scraping process and returns a list of extracted movies.
def scrape(self) -> List[Movie]
return
List[Movie]
List of Movie objects with data obtained from scraping.

Implementation Example

See ImdbScraper for the concrete implementation.

UseCaseInterface

Base interface for all application use cases.

Class Definition

from abc import ABC, abstractmethod
from typing import Any

class UseCaseInterface(ABC):
    @abstractmethod
    def execute(self, data: Any) -> None:
        pass
Source: domain/interfaces/use_case_interface.py:4-25

Methods

execute

Executes the main use case logic.
def execute(self, data: Any) -> None
data
Any
required
Data required to execute the use case. Can be an object, dictionary, or other type depending on the context.
return
None
Use cases perform side effects (e.g., saving to database) and return nothing.

Implementation Examples

See Use Cases for concrete implementations:
  • SaveMovieWithActorsCsvUseCase
  • SaveMovieWithActorsPostgresUseCase
  • CompositeSaveMovieWithActorsUseCase

ProxyProviderInterface

Interface for proxy providers supporting various proxy types.

Class Definition

from abc import ABC, abstractmethod
from typing import Optional, Dict

class ProxyProviderInterface(ABC):
    @abstractmethod
    def get_proxy(self) -> Optional[Dict[str, str]]:
        pass
    
    @abstractmethod
    def get_proxy_location(self, proxy: Optional[Dict[str, str]]) -> tuple[str, str, str]:
        pass
Source: domain/interfaces/proxy_interface.py:5-35

Methods

get_proxy

Returns the current proxy configuration to use.
def get_proxy(self) -> Optional[Dict[str, str]]
return
Optional[Dict[str, str]]
Proxy configuration dictionary (e.g., {'http': 'socks5h://127.0.0.1:9050', 'https': 'socks5h://127.0.0.1:9050'}), or None for direct connection.

get_proxy_location

Retrieves geographic information associated with the proxy.
def get_proxy_location(self, proxy: Optional[Dict[str, str]]) -> tuple[str, str, str]
proxy
Optional[Dict[str, str]]
Proxy configuration dictionary.
return
tuple[str, str, str]
Tuple containing (public IP, city, country).

Implementation Example

See ProxyProvider for the concrete implementation.

TorInterface

Interface for Tor network control.

Class Definition

from abc import ABC, abstractmethod

class TorInterface(ABC):
    @abstractmethod
    def rotate_ip(self) -> str:
        pass
    
    @abstractmethod
    def get_current_ip(self) -> str:
        pass
Source: domain/interfaces/tor_interface.py:3-29

Methods

rotate_ip

Rotates the current Tor IP address and returns the new public IP.
def rotate_ip(self) -> str
return
str
New public IP address obtained after rotation.

get_current_ip

Retrieves the current public IP address without performing rotation.
def get_current_ip(self) -> str
return
str
Current Tor public IP address.

Implementation Example

See TorRotator for the concrete implementation.

Benefits of Interface Segregation

Dependency Inversion

High-level modules (use cases, scrapers) depend on abstractions, not concrete implementations:
class ImdbScraper(ScraperInterface):
    def __init__(
        self,
        use_case: UseCaseInterface,  # Depends on interface
        proxy_provider: ProxyProviderInterface,  # Not concrete class
        tor_rotator: TorInterface
    ):
        ...

Testability

Easy to create mock implementations for testing:
class MockProxyProvider(ProxyProviderInterface):
    def get_proxy(self) -> Optional[Dict[str, str]]:
        return None  # Simulate direct connection
    
    def get_proxy_location(self, proxy) -> tuple[str, str, str]:
        return "127.0.0.1", "Test City", "Test Country"

Flexibility

Swap implementations without changing dependent code:
# Use Tor
scraper = ImdbScraper(
    use_case=my_use_case,
    proxy_provider=TorRotator(),
    tor_rotator=tor_controller
)

# Or use custom proxy
scraper = ImdbScraper(
    use_case=my_use_case,
    proxy_provider=CustomProxyProvider(),
    tor_rotator=tor_controller
)

Build docs developers (and LLMs) love