Resource Factory
This guide is for developers who want to construct Pydantic models from FHIR structure definitions, implementation guides, and packages. You'll learn to use Fhircraft's factory system to build type-safe FHIR models from various sources, manage repositories, and handle complex scenarios like custom profiles and multiple FHIR versions.
Prerequisites
Before diving into this guide, make sure you understand:
- Basic Fhircraft concepts from the FHIR Resources Overview
- FHIR structure definitions and how they define resource shapes
- Python imports and package management
Overview
Fhircraft transforms FHIR structure definitions into usable Python Pydantic models that provide type safety, validation, and easy integration with your applications. The factory system supports multiple construction methods:
- Direct Construction - Build models from loaded structure definitions
- Canonical URL Resolution - Resolve definitions from URLs with fallback strategies
- FHIR Package Loading - Load complete implementation guides and profiles
- Repository Management - Organize multiple definitions with version control
Basic Model Construction
Direct Model Construction from Structure Definitions
Use construct_resource_model
to create Pydantic models from FHIR structure definitions. This method provides complete control and security by working with local files.
Requirements:
- Structure definitions must include a
snapshot
section (not just differential) - Fhircraft automatically detects and handles FHIR version differences (R4, R4B, R5)
from fhircraft.fhir.resources.factory import construct_resource_model
from fhircraft.utils import load_file
# Load structure definition from local file
structure_def = load_file('patient_profile.json')
# Create the Pydantic model
PatientModel = construct_resource_model(structure_definition=structure_def)
# Use the model with automatic validation
patient = PatientModel(
name=[{"given": ["John"], "family": "Doe"}],
birthDate="1990-05-15",
gender="male"
)
print(f"Created model for: {structure_def['name']}")
Repository-Based Management
For applications with multiple structure definitions, use the repository system for organized management:
from fhircraft.fhir.resources.factory import factory
# Configure repository with multiple sources
factory.configure_repository(
directory="./fhir-profiles", # Load all JSON/YAML files from directory
files=["./custom-profile.json"], # Include specific files
internet_enabled=True # Enable internet fallback for canonical URLs
)
# Reference models by their canonical URLs
CustomPatient = factory.construct_resource_model(
canonical_url="http://example.org/StructureDefinition/CustomPatient"
)
# Use the constructed model
patient = CustomPatient(
name=[{"given": ["Alice"], "family": "Johnson"}],
gender="female"
)
Canonical URL Resolution
Canonical URLs are globally unique identifiers for FHIR conformance resources. Fhircraft's repository system uses a smart resolution strategy that checks local definitions first, then falls back to internet downloads when needed.
Basic URL Resolution
Canonical URLs provide a standardized way to reference FHIR structure definitions. Fhircraft will attempt to resolve these URLs automatically, checking local sources first and falling back to internet downloads when needed:
from fhircraft.fhir.resources.factory import construct_resource_model
# Construct from official FHIR Patient resource
patient_model = construct_resource_model(
canonical_url="http://hl7.org/fhir/StructureDefinition/Patient"
)
# Construct from a custom profile (will try local first, then download)
custom_profile_model = construct_resource_model(
canonical_url="http://example.org/fhir/StructureDefinition/MyPatientProfile"
)
# Construct from HL7 implementation guides
us_core_patient = construct_resource_model(
canonical_url="http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
)
# Specify exact versions using the canonical URL format
versioned_patient = construct_resource_model(
canonical_url="http://hl7.org/fhir/StructureDefinition/Patient|4.3.0"
)
Multi-Source Resolution Strategy
Fhircraft follows a prioritized lookup strategy for robust definition resolution:
Resolution Priority
- Local Definitions - Structure definitions loaded from local files (highest priority)
- Package Registry - Definitions from loaded FHIR packages (medium priority)
- Internet Fallback - Downloads from canonical URLs if not found locally (lowest priority)
- Version Support - Handles semantic versioning with latest version tracking
- Caching - Automatically caches downloaded definitions for better performance
Network Dependencies
When using canonical URLs for definitions not available locally, ensure you have internet connectivity. For production environments, consider pre-loading all required structure definitions locally.
FHIR Package Integration
FHIR packages contain published specifications like US Core, International Patient Summary, and other Implementation Guides. Fhircraft automatically downloads, caches, and integrates these packages into your development workflow.
Quick Start with Packages
The fastest way to get started with FHIR packages is to load a popular implementation guide like US Core. This example shows the complete workflow from package loading to model usage:
from fhircraft.fhir.resources.factory import ResourceFactory
# Enable package loading
factory = ResourceFactory(enable_packages=True)
# Load US Core Implementation Guide version 5.0.1
factory.load_package("hl7.fhir.us.core", "5.0.1")
# Create a US Core Patient model with enhanced validation
USCorePatient = factory.construct_resource_model(
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
)
# Use the model with US Core constraints
patient = USCorePatient(
name=[{"given": ["John"], "family": "Doe"}],
gender="male",
# US Core requires identifier
identifier=[{
"system": "http://example.org/mrn",
"value": "12345"
}]
)
print(f"Created US Core patient: {patient.name[0].given[0]} {patient.name[0].family}")
Batch Package Loading
Load multiple packages efficiently for comprehensive profile support:
# Configure factory with multiple packages at once
factory.configure_repository(
directory="local_profiles/", # Load local files first
packages=[
"hl7.fhir.r4.core", # Latest version of FHIR R4 core
("hl7.fhir.us.core", "5.0.1"), # Specific version of US Core
("hl7.fhir.uv.ips", "1.1.0"), # International Patient Summary
("hl7.fhir.us.mcode", "3.0.0"), # Minimal Common Oncology Data Elements
],
internet_enabled=True
)
# All structure definitions from loaded packages are now available
USCorePatient = factory.construct_resource_model(
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
)
IPSPatient = factory.construct_resource_model(
"http://hl7.org/fhir/uv/ips/StructureDefinition/Patient-uv-ips"
)
Common FHIR Packages
Fhircraft can download and extract any FHIR packages from the FHIR Package Registry. Here is a collection of commonly used FHIR packages.
Package | Description | Use Case |
---|---|---|
hl7.fhir.r4.core |
FHIR R4 core specification | Base FHIR R4 resources |
hl7.fhir.r5.core |
FHIR R5 core specification | Base FHIR R5 resources |
hl7.fhir.us.core |
US Core Implementation Guide | US healthcare interoperability |
hl7.fhir.uv.ips |
International Patient Summary | Global patient summaries |
hl7.fhir.us.mcode |
Minimal Common Oncology Data Elements | Cancer care data |
hl7.fhir.uv.smart-app-launch |
SMART App Launch | OAuth2-based app authorization |
Package Management Operations
Once you've loaded packages, you'll often need to inspect what's available, manage versions, or clean up when packages are no longer needed. These operations help you maintain control over your loaded packages:
# Check what packages are loaded
packages = factory.get_loaded_packages()
print("Loaded packages:", packages)
# Check if specific package is loaded
if factory.has_package("hl7.fhir.us.core"):
print("US Core is available")
# Remove packages when no longer needed
factory.remove_package("hl7.fhir.us.core", "5.0.1")
# Clear entire package cache
factory.clear_package_cache()
print(f"Cache cleared, {len(factory.get_loaded_packages())} packages remaining")
Error Handling for Package Operations
Package loading can fail for various reasons - network issues, missing packages, or incorrect versions. Robust applications should handle these errors gracefully and provide helpful feedback:
from fhircraft.fhir.packages import PackageNotFoundError, FHIRPackageRegistryError
def load_package_safely(package_name: str, version: str = None) -> bool:
"""Safely load a FHIR package with error handling."""
try:
factory.load_package(package_name, version)
print(f"Successfully loaded {package_name} {version or 'latest'}")
return True
except PackageNotFoundError as e:
print(f"Package not found: {e}")
return False
except FHIRPackageRegistryError as e:
print(f"Registry error: {e}")
return False
except Exception as e:
print(f"Unexpected error loading package: {e}")
return False
# Usage
success = load_package_safely("hl7.fhir.us.core", "5.0.1")
if success:
# Proceed with model construction
pass
Advanced Package Management
Configuration Options
For production applications or specialized environments, you may need to customize the factory behavior. These configuration options provide control over package sources, timeouts, and access permissions:
# Configure factory with custom settings
factory = ResourceFactory(
enable_packages=True,
registry_base_url="https://packages.fhir.org", # Default FHIR package registry
timeout=30.0, # Request timeout in seconds
internet_enabled=True # Allow internet access
)
# Configure repository with comprehensive options
factory.configure_repository(
directory="./local_profiles", # Local structure definitions
packages=[
"hl7.fhir.r4.core", # Load latest version
("hl7.fhir.us.core", "5.0.1"), # Load specific version
],
registry_base_url="https://packages.fhir.org",
internet_enabled=True,
timeout=30.0
)
Direct Package Registry Access
For advanced scenarios, interact directly with the FHIR package registry:
from fhircraft.fhir.packages import FHIRPackageRegistryClient
# Create client for direct registry interaction
client = FHIRPackageRegistryClient()
# List available versions of a package
package_info = client.list_package_versions("hl7.fhir.us.core")
print(f"Latest version: {package_info.dist_tags.latest}")
print(f"All versions: {list(package_info.versions.keys())}")
# Download package manually (for custom processing)
package_data = client.download_package("hl7.fhir.us.core", "5.0.1")
print(f"Downloaded package size: {len(package_data)} bytes")
Working with Multiple Package Sources
For complex applications, you might need to combine multiple sources of structure definitions - local files, different packages, and internet resources. The composite repository provides a unified interface:
from pathlib import Path
from fhircraft.fhir.resources.repository import CompositeStructureDefinitionRepository
# Create repository with all sources enabled
repo = CompositeStructureDefinitionRepository(
enable_packages=True,
internet_enabled=True
)
# Load from multiple sources
repo.load_from_directory("local_profiles/")
repo.load_package("hl7.fhir.us.core", "5.0.1")
# Getting a structure definition checks sources in priority order
patient_def = repo.get("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient")
if patient_def:
print(f"Found definition for: {patient_def['name']}")
Integrated Construction Workflow
Combine package loading with model construction for complete workflows:
# Complete workflow: Load packages and construct models
factory = ResourceFactory(enable_packages=True)
# Load required packages for comprehensive coverage
packages_to_load = [
("hl7.fhir.us.core", "5.0.1"),
("hl7.fhir.uv.ips", "1.1.0")
]
for package_name, version in packages_to_load:
factory.load_package(package_name, version)
# Construct models from package definitions
USCorePatient = factory.construct_resource_model(
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"
)
USCoreCondition = factory.construct_resource_model(
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"
)
IPSPatient = factory.construct_resource_model(
"http://hl7.org/fhir/uv/ips/StructureDefinition/Patient-uv-ips"
)
# Use the models with proper validation
us_patient = USCorePatient(
identifier=[{"system": "http://example.com", "value": "123"}],
name=[{"family": "Doe", "given": ["John"]}],
gender="male"
)
print(f"Created US Core patient: {us_patient.id}")
Model Caching and Performance
Automatic Model Caching
Fhircraft automatically caches constructed models based on their canonical URLs to improve performance:
from fhircraft.fhir.resources.factory import construct_resource_model, factory
# First call - downloads and constructs the model
patient_model_1 = construct_resource_model(
canonical_url="http://hl7.org/fhir/StructureDefinition/Patient"
)
# Second call - returns cached model (much faster)
patient_model_2 = construct_resource_model(
canonical_url="http://hl7.org/fhir/StructureDefinition/Patient"
)
# Verify they're the same cached instance
assert patient_model_1 is patient_model_2
print("Models are identical (cached)")
# Clear the cache when needed
factory.clear_cache()
# This will now reconstruct the model
patient_model_3 = construct_resource_model(
canonical_url="http://hl7.org/fhir/StructureDefinition/Patient"
)
print("Model reconstructed after cache clear")
Cache Management Best Practices
When to Clear Cache
Clear the cache when:
- Structure definitions have been updated - Ensure you're using the latest versions
- During development/testing - Ensure fresh model construction between test runs
- Memory optimization - Free memory when working with many different profiles
- Version switching - When changing between different versions of the same profile
Performance Considerations
- Cache hits are ~1000x faster than model reconstruction
- Memory usage grows with the number of unique canonical URLs
- Thread safety - Cache is safe for concurrent read access
- Production deployment - Consider warming the cache with frequently used models
Multi-Version FHIR Support
Working with Different FHIR Releases
Fhircraft automatically detects the FHIR version from structure definitions and uses the appropriate data types:
from fhircraft.fhir.resources.factory import construct_resource_model
# R4 Patient model
r4_patient_model = construct_resource_model(
canonical_url="http://hl7.org/fhir/R4/StructureDefinition/Patient"
)
# R4B Patient model
r4b_patient_model = construct_resource_model(
canonical_url="http://hl7.org/fhir/R4B/StructureDefinition/Patient"
)
# R5 Patient model
r5_patient_model = construct_resource_model(
canonical_url="http://hl7.org/fhir/R5/StructureDefinition/Patient"
)
# Each model uses version-specific data types and constraints
r4_patient = r4_patient_model(name=[{"family": "Smith"}])
r5_patient = r5_patient_model(name=[{"family": "Smith"}])
print(f"R4 Patient type: {type(r4_patient)}")
print(f"R5 Patient type: {type(r5_patient)}")
Direct Version-Specific Imports
For explicit version control, import pre-built models for specific FHIR releases:
# Direct imports for specific releases
from fhircraft.fhir.resources.datatypes.R4.complex_types import Patient as PatientR4
from fhircraft.fhir.resources.datatypes.R4B.complex_types import Patient as PatientR4B
from fhircraft.fhir.resources.datatypes.R5.complex_types import Patient as PatientR5
# Use the appropriate model for your data version
patient_r4 = PatientR4(name=[{"family": "Smith"}])
patient_r5 = PatientR5(name=[{"family": "Smith"}])
# Each model enforces version-specific constraints
print(f"R4 Patient resourceType: {patient_r4.resourceType}")
print(f"R5 Patient resourceType: {patient_r5.resourceType}")
Repository System Management
Basic Repository Configuration
The repository system provides efficient storage, versioning, and retrieval of structure definitions:
from fhircraft.fhir.resources.factory import factory
# Configure repository with multiple sources
factory.configure_repository(
directory="/path/to/structure/definitions", # Load all JSON files from directory
files=[ # Load specific files
"/path/to/custom/profile1.json",
"/path/to/custom/profile2.json"
],
definitions=[structure_def_dict], # Load from pre-loaded dictionaries
internet_enabled=True # Allow internet fallback
)
# Use canonical URLs - will check local first, then internet
Patient = factory.construct_resource_model(
canonical_url="http://hl7.org/fhir/StructureDefinition/Patient"
)
Advanced Repository Operations
The repository system provides fine-grained control over how definitions are loaded and managed. These operations are useful for dynamic loading, offline operation, and repository introspection:
from fhircraft.fhir.resources.factory import factory
# Load definitions incrementally
factory.load_definitions_from_directory("/path/to/core/definitions")
factory.load_definitions_from_files("/path/to/custom/profile.json")
# Control internet access dynamically
factory.disable_internet_access() # Offline mode for production
print("Internet access disabled")
# Perform offline operations...
factory.enable_internet_access() # Re-enable for development
print("Internet access restored")
# Check repository status
repository = factory.repository
has_definition = repository.has("http://hl7.org/fhir/StructureDefinition/Patient")
available_versions = repository.get_versions("http://hl7.org/fhir/StructureDefinition/Patient")
latest_version = repository.get_latest_version("http://hl7.org/fhir/StructureDefinition/Patient")
print(f"Patient definition available: {has_definition}")
print(f"Available versions: {available_versions}")
print(f"Latest version: {latest_version}")
Versioned Structure Definitions
The repository system supports FHIR versioning using the canonical URL format url|version
:
from fhircraft.fhir.resources.factory import factory
# Load specific version
patient_v401 = factory.construct_resource_model(
canonical_url="http://hl7.org/fhir/StructureDefinition/Patient|4.0.1"
)
# Load latest version (default behavior)
patient_latest = factory.construct_resource_model(
canonical_url="http://hl7.org/fhir/StructureDefinition/Patient"
)
# Check available versions
versions = factory.repository.get_versions("http://hl7.org/fhir/StructureDefinition/Patient")
print(f"Available versions: {versions}")
# Get version metadata
version_info = factory.repository.get_version_info("http://hl7.org/fhir/StructureDefinition/Patient|4.0.1")
print(f"Version info: {version_info}")
Best Practices
Production Deployment
Production Configuration
For production environments:
- Pre-load all definitions - Load all required structure definitions at application startup
- Disable internet access - Use
factory.disable_internet_access()
to prevent unexpected network calls - Version pinning - Use specific versions in canonical URLs for reproducible builds
- Local storage - Store structure definitions in your application's resources directory
- Cache warming - Pre-construct frequently used models to improve runtime performance
def setup_production_factory() -> ResourceFactory:
"""Configure factory for production use."""
factory = ResourceFactory(
enable_packages=True,
internet_enabled=False # Disable internet for production
)
# Load all required packages with specific versions
required_packages = [
("hl7.fhir.us.core", "5.0.1"),
("hl7.fhir.uv.ips", "1.1.0"),
]
for package_name, version in required_packages:
factory.load_package(package_name, version)
# Pre-construct frequently used models
common_models = [
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient",
"http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition",
]
for canonical_url in common_models:
factory.construct_resource_model(canonical_url)
return factory
Error Handling and Validation
Model construction can fail for various reasons - missing definitions, network issues, or invalid structure definitions. Implementing comprehensive error handling ensures your application remains stable:
def safe_model_construction(canonical_url: str) -> tuple[bool, any]:
"""Safely construct a model with comprehensive error handling."""
try:
model = factory.construct_resource_model(canonical_url)
return True, model
except PackageNotFoundError as e:
print(f"Package not found for {canonical_url}: {e}")
return False, f"Package not found: {e}"
except ValueError as e:
print(f"Invalid structure definition for {canonical_url}: {e}")
return False, f"Invalid definition: {e}"
except Exception as e:
print(f"Unexpected error constructing {canonical_url}: {e}")
return False, f"Construction failed: {e}"
# Usage
success, result = safe_model_construction("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient")
if success:
PatientModel = result
print(f"Successfully constructed model")
else:
error_message = result
print(f"Failed to construct model: {error_message}")
Memory and Performance Optimization
Memory Considerations
- Repository keeps definitions in memory for fast access
- Monitor memory usage with many definitions
- Consider on-demand loading for large applications
- Clear caches periodically if memory becomes a concern
Thread Safety
- Repository is thread-safe for read operations
- Avoid concurrent modifications from multiple threads
- Cache access is atomic for model retrieval
- Package loading should be done in main thread
Troubleshooting
Common Issues and Solutions
Package Not Found
# Issue: PackageNotFoundError when loading package
try:
factory.load_package("hl7.fhir.us.core", "999.0.0") # Non-existent version
except PackageNotFoundError:
print("Check package name and version at https://packages.fhir.org")
Internet Access Issues
# Issue: Cannot download canonical URLs
factory.disable_internet_access()
# Ensure all required definitions are loaded locally
Version Conflicts
# Issue: Multiple versions of same package
factory.remove_package("hl7.fhir.us.core", "4.0.0") # Remove old version
factory.load_package("hl7.fhir.us.core", "5.0.1") # Load new version
Cache Issues
# Issue: Stale cached models
factory.clear_cache() # Clear all cached models
# Reconstruct models with updated definitions
What's Next?
Now that you understand model construction, explore these related topics:
- Resource Models - Learn to create and work with resource instances
- Pydantic FHIR - Understand the technical foundations of FHIR representation
- FHIR Path - Query and manipulate resources with FHIRPath expressions
- FHIR Mapper - Transform external data into FHIR resources
Continue learning: Resource Models →