๐ฏ Configurable Type Discoveryยถ
The Neuroglia framework provides a flexible TypeRegistry system that allows applications to configure which modules should be scanned for domain types (enums, value objects, etc.) without hardcoding patterns in the framework itself.
๐ฏ Overviewยถ
The TypeRegistry replaces hardcoded domain structure assumptions with a clean, configurable approach:
- Framework Agnostic: No domain-specific knowledge in framework code
- Configurable: Applications specify their exact module structure
- Performance Optimized: Only scans registered modules instead of trying dozens of patterns
- Extensible: Supports dynamic type discovery and multiple configuration methods
๐๏ธ Core Componentsยถ
TypeRegistryยถ
The TypeRegistry provides centralized type discovery using the framework's existing utilities:
from neuroglia.core.type_registry import TypeRegistry, get_type_registry
from neuroglia.core.type_finder import TypeFinder
from neuroglia.core.module_loader import ModuleLoader
# Get the global type registry instance
registry = get_type_registry()
# Register modules for type discovery
registry.register_modules([
"domain.entities.enums",
"domain.value_objects",
"shared.types"
])
# Find enum for a value
pizza_size_enum = registry.find_enum_for_value("LARGE")
Enhanced JsonSerializerยถ
The JsonSerializer now accepts configurable type modules:
from neuroglia.serialization.json import JsonSerializer
from neuroglia.hosting.enhanced_web_application_builder import EnhancedWebApplicationBuilder
builder = EnhancedWebApplicationBuilder()
# Configure with specific type modules
JsonSerializer.configure(builder, type_modules=[
"domain.entities.enums", # Main enum module
"domain.entities", # Entity module (for embedded enums)
"domain.value_objects", # Value objects with enums
])
๐ Configuration Methodsยถ
Method 1: Direct Configurationยถ
Configure type modules during JsonSerializer setup:
def configure_application():
builder = EnhancedWebApplicationBuilder()
# Configure JsonSerializer with your domain modules
JsonSerializer.configure(builder, type_modules=[
"myapp.domain.enums", # Primary enumerations
"myapp.domain.entities", # Domain entities
"myapp.domain.value_objects", # Value objects
"myapp.shared.types", # Shared types
"myapp.integration.external" # External API types
])
return builder
Method 2: Post-Configuration Registrationยถ
Register modules after initial configuration:
def configure_with_registration():
builder = EnhancedWebApplicationBuilder()
# Basic configuration
JsonSerializer.configure(builder)
# Register additional type modules
JsonSerializer.register_type_modules([
"myapp.domain.aggregates",
"myapp.domain.value_objects",
"myapp.shared.enums"
])
return builder
Method 3: Direct TypeRegistry Accessยถ
Configure the TypeRegistry directly for advanced scenarios:
def configure_advanced():
from neuroglia.core.type_registry import get_type_registry
# Get the global registry
registry = get_type_registry()
# Register core domain modules
registry.register_modules([
"orders.domain.entities",
"orders.domain.enums"
])
# Register shared library types
registry.register_modules([
"shared_lib.common.enums",
"payment_gateway.types"
])
# Standard JsonSerializer configuration
builder = EnhancedWebApplicationBuilder()
JsonSerializer.configure(builder)
return builder
๐งช Usage Examplesยถ
Mario Pizzeria Configurationยถ
from neuroglia.serialization.json import JsonSerializer
from neuroglia.hosting.enhanced_web_application_builder import EnhancedWebApplicationBuilder
def configure_mario_pizzeria():
builder = EnhancedWebApplicationBuilder()
# Configure with Mario Pizzeria's domain structure
JsonSerializer.configure(builder, type_modules=[
"domain.entities.enums", # PizzaSize, OrderStatus, Priority
"domain.entities", # Pizza, Order entities
"domain.value_objects", # Money, Address value objects
])
return builder
Microservice Configurationยถ
def configure_microservice():
from neuroglia.core.type_registry import get_type_registry
registry = get_type_registry()
# Register internal domain types
registry.register_modules([
"orders.domain.entities",
"orders.domain.enums"
])
# Register external service types we need to deserialize
registry.register_modules([
"payment_service.models",
"inventory_service.types",
"shared_contracts.events"
])
builder = EnhancedWebApplicationBuilder()
JsonSerializer.configure(builder)
return builder
Flat Project Structureยถ
For projects with simple, flat module structure:
def configure_flat_structure():
builder = EnhancedWebApplicationBuilder()
# Simple flat structure: models.py, enums.py, types.py
JsonSerializer.configure(builder, type_modules=[
"models", # Main model types
"enums", # All enumerations
"types", # Custom types
"constants" # Constants and lookups
])
return builder
๐ง Dynamic Type Discoveryยถ
For advanced scenarios, you can dynamically discover and register types:
def dynamic_type_discovery():
from neuroglia.core.type_registry import get_type_registry
from neuroglia.core.type_finder import TypeFinder
from neuroglia.core.module_loader import ModuleLoader
from enum import Enum
registry = get_type_registry()
# Discover all enum types in base modules
base_modules = ["myapp.domain", "myapp.shared"]
for base_module_name in base_modules:
try:
base_module = ModuleLoader.load(base_module_name)
# Find all enum types
enum_types = TypeFinder.get_types(
base_module,
predicate=lambda t: isinstance(t, type) and issubclass(t, Enum) and t != Enum,
include_sub_modules=True,
include_sub_packages=True
)
if enum_types:
print(f"Discovered {len(enum_types)} enum types in {base_module_name}")
# Types are automatically cached when accessed
except ImportError:
print(f"Module {base_module_name} not available")
return registry
๐ก Best Practicesยถ
1. Specific Module Registrationยถ
Register only the modules that contain types you need:
# Good: Specific modules
JsonSerializer.configure(builder, type_modules=[
"domain.entities.enums", # Specific enum module
"domain.value_objects" # Specific value object module
])
# Avoid: Too broad
JsonSerializer.configure(builder, type_modules=[
"domain", # Too broad, includes everything
"application" # Application layer shouldn't have enums
])
2. Layer-Appropriate Registrationยถ
Only register modules from appropriate architectural layers:
# Good: Domain and integration layers
JsonSerializer.configure(builder, type_modules=[
"domain.entities.enums", # Domain layer
"domain.value_objects", # Domain layer
"integration.external_types" # Integration layer for external APIs
])
# Avoid: Application layer
JsonSerializer.configure(builder, type_modules=[
"application.commands", # Commands shouldn't have enums
"application.handlers" # Handlers shouldn't have enums
])
3. Performance Optimizationยถ
Register modules in order of frequency of use:
# Most frequently used enums first
JsonSerializer.configure(builder, type_modules=[
"domain.entities.enums", # Most common: PizzaSize, OrderStatus
"domain.value_objects", # Less common: specialized enums
"shared.constants" # Least common: system constants
])
4. Modular Configurationยถ
For large applications, organize configuration by feature:
def configure_order_types():
return [
"orders.domain.enums",
"orders.domain.entities",
"orders.integration.payment_types"
]
def configure_inventory_types():
return [
"inventory.domain.enums",
"inventory.domain.entities",
"inventory.integration.supplier_types"
]
def configure_application():
builder = EnhancedWebApplicationBuilder()
all_type_modules = (
configure_order_types() +
configure_inventory_types() +
["shared.common.enums"]
)
JsonSerializer.configure(builder, type_modules=all_type_modules)
return builder
๐ Related Documentationยถ
- Data Access - Repository patterns and serialization
- Domain-Driven Design - Domain layer organization
- Dependency Injection - Service configuration patterns
๐งช Testing Configurationยถ
Test your type configuration with different scenarios:
def test_configured_serialization():
"""Test that configured types are discovered correctly"""
from neuroglia.core.type_registry import get_type_registry
registry = get_type_registry()
registry.register_modules(["domain.entities.enums"])
# Test enum discovery
pizza_size_enum = registry.find_enum_for_value("LARGE")
assert pizza_size_enum is not None
assert pizza_size_enum.__name__ == "PizzaSize"
print("โ
Configured type discovery working correctly")
The configurable TypeRegistry approach ensures your application can specify exactly which modules contain domain types, making the framework truly generic while maintaining intelligent type inference capabilities.