Interfaces (Ports)
Interfaces define contracts between the application layer and external dependencies. They enable the Dependency Inversion Principle, allowing business logic to remain independent of infrastructure implementations.Purpose
Interfaces in Soft-Bee API:- Define contracts for repositories and services
- Enable dependency inversion (depend on abstractions, not concretions)
- Allow swapping implementations without changing business logic
- Facilitate testing with mock implementations
- Separate concerns between layers
Interface Types
Soft-Bee uses two main types of interfaces:- Repository Interfaces - Data access contracts
- Service Interfaces - Infrastructure service contracts
Repository Interfaces
User Repository Interface
TheIUserRepository defines all data access operations for users:
src/features/auth/application/interfaces/repositories/user_repository.py:5
Repository Operations
CRUD Operations
save(user: User)- Create or update userfind_by_id(user_id: str)- Retrieve by IDdelete(user_id: str)- Remove user
Query Operations
find_by_email(email: str)- Find by email addressfind_by_username(username: str)- Find by usernameexists_by_email(email: str)- Check email existenceexists_by_username(username: str)- Check username existence
Token Management
add_refresh_token(user_id, token)- Store refresh tokenremove_refresh_token(user_id, token)- Invalidate refresh tokenhas_refresh_token(user_id, token)- Verify token validity
Session Management
update_last_login(user_id)- Update login timestamp
Service Interfaces
Token Service Interface
TheITokenService defines JWT token operations:
src/features/auth/application/interfaces/services/token_service.py:5
Token Operations
Token Creation
create_access_token(data, expires_in)- Generate short-lived access token (default 15 minutes)create_refresh_token(data, expires_in)- Generate long-lived refresh token (default 30 days)
Token Validation
verify_token(token)- Validate signature and expiration, return payloaddecode_token(token)- Decode without validationis_token_expired(token)- Check expiration statusget_token_expiry(token)- Get expiration timestamp
Dependency Inversion in Action
Use Case Dependency Injection
Use cases depend on interfaces, not implementations:- Constructor accepts interfaces (
IUserRepository,ITokenService) - Use case doesn’t know about SQLAlchemy, JWT libraries, or Flask
- Can be tested with mock implementations
- Infrastructure can be swapped without changing use case code
Infrastructure Implementation
Concrete implementations live in the infrastructure layer:Dependency Injection Container
Dependencies are wired together at application startup:Benefits of Interfaces
1. Testability
Easy to test with mock implementations:2. Flexibility
Swap implementations without changing business logic:3. Framework Independence
Business logic doesn’t depend on frameworks:4. Clear Boundaries
Explicit contracts between layers:Design Patterns
Repository Pattern
Encapsulates data access logic:- Provides collection-like interface for domain objects
- Hides database implementation details
- Enables domain-driven design
Port-Adapter Pattern (Hexagonal Architecture)
- Ports (Interfaces) - Define contracts
- Adapters (Implementations) - Connect to external systems
- Application core depends only on ports
- Adapters depend on and implement ports
Dependency Inversion Principle (SOLID)
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Best Practices
- Use Abstract Base Classes - Enforce interface contracts with
ABCand@abstractmethod - Return Domain Types - Repository methods return domain entities, not database models
- Keep Interfaces Cohesive - Group related operations in one interface
- Minimal Dependencies - Interfaces should only import domain types
- Consistent Naming - Use
Iprefix for interfaces (e.g.,IUserRepository) - Document Behavior - Include docstrings explaining expected behavior
- Fail Explicitly - Define what exceptions implementations should raise
Common Pitfalls
Leaky Abstractions
Over-Specification
See Also
- Use Cases - Business logic that uses interfaces
- Domain Entities - Types returned by repositories
- Infrastructure Layer - Concrete implementations
- Dependency Injection - Wiring interfaces to implementations