The Instance Validator relies on an implementation of an interface called IValidationSupport to load StructureDefinitions, validate codes, etc.
By default, an implementation of this interface called DefaultProfileValidationSupport is used. This implementation simply uses the built-in official FHIR definitions to validate against (and in many cases, this is good enough).
However, if you have needs beyond simply validating against the core FHIR specification, you may wish to use something more.
There are a several implementations of the IValidationSupport interface built into HAPI FHIR that can be used, typically in a chain.
This module can be used to combine multiple implementations together so that for every request, each support class instance in the chain is tried in sequence. Note that nearly all methods in the IValidationSupport interface are permitted to return null
if they are not able to service a particular method call. So for example, if a call to the validateCode
method is made, the validator will try each module in the chain until one of them returns a non-null response.
The following chaining logic is used:
fetchAll...
methods such as fetchAllConformanceResources()
and fetchAllStructureDefinitions()
will call every method in the chain in order, and aggregate the results into a single list to return.validateCode(...)
and lookupCode(...)
will first test each module in the chain using theisCodeSystemSupported(...)
or isValueSetSupported(...)
methods (depending on whether a ValueSet URL is present in the method parameters) and will invoke any methods in the chain which return that they can handle the given CodeSystem/ValueSet URL. The first non-null value returned by a method in the chain that can support the URL will be returned to the caller.The following caching logic is used if caching is enabled using CacheConfiguration
. You can use CacheConfiguration.disabled()
if you want to disable caching.
fetchAllStructureDefinitions()
and fetchStructureDefinition(...)
are cached in a non-expiring cache. This is because the FhirInstanceValidator
module makes assumptions that these objects will not change for the lifetime of the validator for performance reasons.fetchAll...
methods including fetchAllConformanceResources()
and fetchAllSearchParameters()
cache their results in an expiring cache, but will refresh that cache asynchronously.generateSnapshot(...)
are not cached, as this method is generally called in contexts where the results are cached.Note that caching functionality used to be provided by a separate provider called {@literal CachingValidationSupport} but that functionality has been moved into this class as of HAPI FHIR 8.0.0, because it is possible to provide a more efficient chain when these functions are combined.
This module supplies the built-in FHIR core structure definitions, including both FHIR resource definitions (StructureDefinition resources) and FHIR built-in vocabulary (ValueSet and CodeSystem resources).
This module acts as a simple terminology service that can validate codes against ValueSet and CodeSystem resources purely in-memory (i.e. with no database). This is sufficient in many basic cases, although it is not able to validate CodeSystems with external content (i.e CodeSystems where the CodeSystem.content
field is external
, such as the LOINC and SNOMED CT CodeSystems).
This module contains a series of HashMaps that store loaded conformance resources in memory. Typically this is initialized at startup in order to add custom conformance resources into the chain.
This module can be used to load FHIR NPM Packages and supply the conformance resources within them to the validator. See Validating Using Packages for am example of how to use this module.
This module generates StructureDefinition snapshots as needed. This should be added to your chain if you are working wiith differential StructureDefinitions that do not include the snapshot view.
This module validates codes in CodeSystems that are not distributed with the FHIR specification because they are difficult to distribute but are commonly used in FHIR resources.
The following table lists vocabulary that is validated by this module:
Name | Canonical URLs | Validation Details |
---|---|---|
USPS State Codes |
ValueSet: (...)/ValueSet/us-core-usps-state
CodeSystem: https://www.usps.com/ |
Codes are validated against a built-in list of valid state codes. |
MimeTypes (BCP-13) |
ValueSet: (...)/ValueSet/mimetypes
CodeSystem: urn:ietf:bcp:13
|
Codes are not validated, but are instead assumed to be correct. Improved validation should be added in the future, please get in touch if you would like to help. |
Languages (BCP-47) |
ValueSet: (...)/ValueSet/languages
ValueSet: (...)/ValueSet/all-languages CodeSystem: urn:ietf:bcp:47
|
Codes are validated against the respective ValueSet. Support for two different ValueSets is provided: The languages ValueSet provides a collection of commonly used language codes. Only codes explicitly referenced in this ValueSet are considered valid. The all-languages ValueSet accepts any valid BCP-47 code. Codes are validated using data supplied by the Language Subtype Registry project. |
Countries (ISO 3166) | CodeSystem: urn:iso:std:iso:3166 | Codes are validated against a built-in list of valid ISO 3166 codes. Both Alpha-2 (two character) and Alpha-3 (three character) variants are supported. |
Unified Codes for Units of Measure (UCUM) |
ValueSet: (...)/ValueSet/ucum-units
CodeSystem: http://unitsofmeasure.org
|
Codes are validated using the UcumEssenceService provided by the UCUM Java library. |
This module validates codes using a remote FHIR-based terminology server.
This module will invoke the following operations on the remote terminology server:
This validation support module may be placed at the end of a ValidationSupportChain in order to configure the validator to generate a warning if a resource being validated contains an unknown code system.
Note that this module must also be activated by calling setAllowNonExistentCodeSystem(true) in order to specify that unknown code systems should be allowed.
This module is deprecated and no longer provides any functionality. Caching is provided by ValidationSupportChain.
The IValidationSupport instance passed to the FhirInstanceValidator will often resemble the chain shown in the diagram below. In this diagram:
The following snippet shows how to supply custom definitions to the validator.
FhirContext ctx = FhirContext.forR4();
// Create a chain that will hold our modules and caches the
// values they supply
ValidationSupportChain supportChain = new ValidationSupportChain();
// DefaultProfileValidationSupport supplies base FHIR definitions. This is generally required
// even if you are using custom profiles, since those profiles will derive from the base
// definitions.
DefaultProfileValidationSupport defaultSupport = new DefaultProfileValidationSupport(ctx);
supportChain.addValidationSupport(defaultSupport);
// This module supplies several code systems that are commonly used in validation
supportChain.addValidationSupport(new CommonCodeSystemsTerminologyService(ctx));
// This module implements terminology services for in-memory code validation
supportChain.addValidationSupport(new InMemoryTerminologyServerValidationSupport(ctx));
// Create a PrePopulatedValidationSupport which can be used to load custom definitions.
// In this example we're loading two things, but in a real scenario we might
// load many StructureDefinitions, ValueSets, CodeSystems, etc.
PrePopulatedValidationSupport prePopulatedSupport = new PrePopulatedValidationSupport(ctx);
prePopulatedSupport.addStructureDefinition(someStructureDefnition);
prePopulatedSupport.addValueSet(someValueSet);
// Add the custom definitions to the chain
supportChain.addValidationSupport(prePopulatedSupport);
// Create a validator using the FhirInstanceValidator module. We can use this
// validator to perform validation
FhirInstanceValidator validatorModule = new FhirInstanceValidator(supportChain);
FhirValidator validator = ctx.newValidator().registerValidatorModule(validatorModule);
ValidationResult result = validator.validateWithResult(input);
The following snippet shows how to leverage a remote (FHIR-based) terminology server, by making REST calls to the external service when codes need to be validated.
FhirContext ctx = FhirContext.forR4();
// Create a chain that will hold our modules
ValidationSupportChain supportChain = new ValidationSupportChain();
// DefaultProfileValidationSupport supplies base FHIR definitions. This is generally required
// even if you are using custom profiles, since those profiles will derive from the base
// definitions.
DefaultProfileValidationSupport defaultSupport = new DefaultProfileValidationSupport(ctx);
supportChain.addValidationSupport(defaultSupport);
// Create a module that uses a remote terminology service
RemoteTerminologyServiceValidationSupport remoteTermSvc = new RemoteTerminologyServiceValidationSupport(ctx);
remoteTermSvc.setBaseUrl("http://hapi.fhir.org/baseR4");
supportChain.addValidationSupport(remoteTermSvc);
// Create a validator using the FhirInstanceValidator module. We can use this
// validator to perform validation
FhirInstanceValidator validatorModule = new FhirInstanceValidator(supportChain);
FhirValidator validator = ctx.newValidator().registerValidatorModule(validatorModule);
ValidationResult result = validator.validateWithResult(input);