Interfaces and Protocols
Relevant source files
The following files were used as context for generating this wiki page:
The flext-ldap library utilizes a rigorous structural typing approach to define its interfaces and protocols. This architecture ensures that the domain logic remains independent of specific model implementations or third-party library constraints (such as ldap3). By leveraging Python's Protocol and @runtime_checkable decorators, the system provides clear contracts for connection management, search operations, and entry manipulation.
The protocols are organized into a layered hierarchy, moving from basic domain types to high-level service and handler interfaces. This structure supports Clean Architecture principles by allowing services to depend on abstractions rather than concrete implementations.
Sources: src/flext_ldap/protocols.py:12-45, examples/README.md:27-32
Protocol Hierarchy and Layers
The protocol system is divided into three primary layers to manage complexity and dependencies:
- Layer 0 (Domain Protocols): Foundation-level interfaces for basic data structures like
LdapBatchStats,ConnectionConfig, andSearchOptions. These have no internal dependencies within the project. - Layer 1 (Service Protocols): Functional interfaces for core services such as
LdapClient,LdapAdapter, andLdapConnection. These may utilize Layer 0 protocols. - Layer 2 (Handler Protocols): High-level interfaces for complex workflows, built upon the lower layers.
The diagram below illustrates the relationship between these layers and their typical interaction flow.
The diagram shows how high-level service protocols consume structural domain protocols to define their operational contracts.
Sources: src/flext_ldap/protocols.py:38-45, src/flext_ldap/protocols.py:73-200
Core Service Interfaces
LdapClient Protocol
The LdapClient is the primary interface for users of the library. It defines methods for standard LDAP CRUD operations and connection lifecycle management. It is designed to be used as a context manager.
| Method | Parameters | Return Type | Description |
|---|---|---|---|
connect | connection_config, **kwargs | p.Result[bool] | Establishes connection to the server. |
add | entry | p.Result[OperationResult] | Creates a new LDAP entry. |
search | search_options, server_type | p.Result[SearchResult] | Executes a search based on criteria. |
modify | dn, changes | p.Result[OperationResult] | Updates an existing entry. |
delete | dn | p.Result[OperationResult] | Removes an entry from the directory. |
batch_upsert | entries, **kwargs | p.Result[LdapBatchStats] | Performs bulk updates/inserts. |
Sources: src/flext_ldap/protocols.py:168-292
LdapAdapter Protocol
The LdapAdapter serves as the Dependency Inversion Principle (DIP) boundary. It allows services to interact with third-party libraries (specifically ldap3) without direct imports in the service layer.
The sequence diagram demonstrates the role of the LdapAdapter in isolating the domain services from the underlying ldap3 implementation.
Sources: src/flext_ldap/protocols.py:294-340, tests/unit/test_utilities.py:125-135
Data Transfer Objects and Configuration
Interfaces for configuration and operation results are defined to ensure consistency across the library.
Search and Connection Models
The project uses Pydantic-based models that satisfy the structural protocols defined in the protocols module.
| Model | Key Fields | Constraints |
|---|---|---|
ConnectionConfig | host, port, use_ssl, use_tls | use_ssl and use_tls are mutually exclusive. |
SearchOptions | base_dn, scope, filter_str | base_dn must be non-empty. |
LdapBatchStats | synced, failed, skipped | All counters must be non-negative integers. |
Sources: src/flext_ldap/_models/ldap.py:22-48, src/flext_ldap/_models/ldap.py:73-85, src/flext_ldap/_models/ldap.py:126-136
Operational Contracts
Specific structural contracts are enforced at service boundaries to guarantee data integrity, such as the ServiceContracts.EntryContract, which requires a validated dn and attributes mapping.
@runtime_checkable
class EntryContract(Protocol):
"""Structural LDAP entry contract for service boundaries."""
dn: str
attributes: t.MappingKV[str, t.StrSequence]
Sources: src/flext_ldap/protocols.py:535-544
External Library Integration (ldap3)
The protocols define structural contracts for ldap3 objects. This allows the codebase to type-check against these objects without importing the actual ldap3 classes, maintaining a clean dependency tree.
Ldap3Connection: Defines methods likebind(),unbind(),add(),delete(), andsearch().Ldap3Entry: Provides access toentry_dnandentry_attributes_as_dict.Ldap3Attribute: Exposes thevaluesand the resolvedvalueof an attribute.
Sources: src/flext_ldap/protocols.py:406-460, src/flext_ldap/protocols.py:488-500
Conclusion
The interfaces and protocols of flext-ldap provide a robust, decoupled architecture that simplifies LDAP operations while maintaining strict type safety. By utilizing layered structural typing, the system remains adaptable to different LDAP server types (e.g., OpenLDAP, OID, OUD) while shielding the developer from the complexities of underlying client libraries. This design pattern ensures that enterprise-grade patterns like Repository and Specification can be implemented cleanly across the project.
Sources: examples/README.md:12-25, src/flext_ldap/protocols.py:12-35