Ignixa.Validation
0.5.2
dotnet add package Ignixa.Validation --version 0.5.2
NuGet\Install-Package Ignixa.Validation -Version 0.5.2
<PackageReference Include="Ignixa.Validation" Version="0.5.2" />
<PackageVersion Include="Ignixa.Validation" Version="0.5.2" />
<PackageReference Include="Ignixa.Validation" />
paket add Ignixa.Validation --version 0.5.2
#r "nuget: Ignixa.Validation, 0.5.2"
#:package Ignixa.Validation@0.5.2
#addin nuget:?package=Ignixa.Validation&version=0.5.2
#tool nuget:?package=Ignixa.Validation&version=0.5.2
Ignixa.Validation
FHIR validation system with four validation depth levels.
Architecture
Four Validation Depth Levels (ADR-2527):
| Depth | Checks | Use Case |
|---|---|---|
| Minimal | JSON structure, required fields | CREATE/UPDATE (blocking), bulk ingestion |
| Compatibility | + Cardinality, types (lenient URIs) | Microsoft FHIR Server migration |
| Spec | + Required terminology, absolute URIs | CREATE/UPDATE (blocking) |
| Full | + FHIRPath invariants, all bindings | $validate (async), compliance testing |
Quick Start
Profile-aware validation (IG support)
To validate a resource against an Implementation Guide profile declared in
Resource.meta.profile, layer the IG package's profiles + ValueSets on top
of the base spec and use ProfileAwareValidationSchemaResolver:
using Ignixa.PackageManagement.Infrastructure;
using Ignixa.Validation.Schema;
using Ignixa.Validation.Services;
// 1. Load an IG package via Ignixa.PackageManagement.
// (See Ignixa.PackageManagement for NpmPackageLoader + PackageExtractor.)
// extractedResources: IReadOnlyList<ExtractedResource>
// 2. Layer the IG profiles on top of the base spec.
var baseSchema = new R4CoreSchemaProvider();
var schemaProvider = new ProfileLayeredSchemaProvider(baseSchema, extractedResources);
// 3. Layer the IG ValueSets on top of the base spec terminology.
var packageVs = new PackageValueSetSource(extractedResources);
var terminology = new InMemoryTerminologyService(
primary: baseSchema.ValueSetProvider,
additional: new[] { (IValueSetProvider)packageVs });
// 4. Build the resolver chain.
var inner = new StructureDefinitionSchemaResolver(schemaProvider, terminologyService: terminology);
var cached = new CachedValidationSchemaResolver(inner);
var profileAware = new ProfileAwareValidationSchemaResolver(cached);
// 5. Resolve a schema that composes base + every profile declared in meta.profile.
var element = sourceNode.ToElement(schemaProvider);
var schema = profileAware.ResolveForElement(element);
// 6. Validate.
var settings = new ValidationSettings { Depth = ValidationDepth.Spec };
var result = schema!.Validate(element, settings, new ValidationState());
ProfileAwareValidationSchemaResolver also implements IValidationSchemaResolver,
so it's a drop-in for any DI registration that previously bound the cached resolver.
The production ValidationServicesRegistration wires it automatically; consumers
that have access to the resource element should call ResolveForElement(element)
to pick up meta.profile composition.
CLI
The ignixa-validator CLI exposes profile-aware validation directly:
ignixa-validator r4 \
--input patient.json \
--package hl7.fhir.us.core@6.1.0 \
--depth spec \
--console
--package id@version is repeatable; multiple packages are layered in declared
order (later wins on profile id collisions). Packages are cached under
%TEMP%/ignixa-validator-package-cache.
Basic Validation (Recommended)
using Ignixa.Validation.Schema;
using Ignixa.Specification.Generated;
using Ignixa.Serialization;
// 1. Get FHIR schema for your version (R4, R4B, R5, or STU3)
var fhirSchema = new R4CoreSchemaProvider();
// 2. Get the type definition for the resource you want to validate
var patientType = fhirSchema.GetTypeDefinition("Patient");
// 3. Build validation schema (automatically creates all checks from StructureDefinition)
var builder = new StructureDefinitionSchemaBuilder();
var validationSchema = builder.BuildSchema(patientType!, fhirSchema);
// 4. Parse and validate your FHIR resource
var json = "{\"resourceType\":\"Patient\",\"id\":\"123\"}";
var sourceNode = JsonSourceNodeFactory.Parse(json).ToSourceNode();
var element = sourceNode.ToElement(fhirSchema);
// 5. Choose validation depth
var settings = new ValidationSettings { Depth = ValidationDepth.Spec };
var state = new ValidationState();
var result = validationSchema.Validate(element, settings, state);
if (!result.IsValid)
{
var operationOutcome = result.ToOperationOutcome();
// Return operationOutcome to client
}
Validating Different Resource Types
using Ignixa.Validation.Schema;
using Ignixa.Specification.Generated;
using Ignixa.Serialization;
var fhirSchema = new R4CoreSchemaProvider();
var builder = new StructureDefinitionSchemaBuilder();
// Validate Observation
var observationType = fhirSchema.GetTypeDefinition("Observation");
var observationSchema = builder.BuildSchema(observationType!, fhirSchema);
var observationJson = "{\"resourceType\":\"Observation\",\"status\":\"final\",\"code\":{}}";
var sourceNode = JsonSourceNodeFactory.Parse(observationJson).ToSourceNode();
var result = observationSchema.Validate(sourceNode.ToElement(fhirSchema));
Validation Depth Guide
Minimal
Fastest validation for high-throughput scenarios:
var settings = new ValidationSettings { Depth = ValidationDepth.Minimal };
Compatibility
For migrating from Microsoft FHIR Server (Firely SDK validation):
var settings = new ValidationSettings { Depth = ValidationDepth.Compatibility };
- Accepts relative URIs in
Coding.system(e.g.,"internal-tags") - Same checks as Spec, but more lenient for migration scenarios
- Use when running Microsoft FHIR Server E2E test suite
Spec
Standard FHIR specification compliance:
var settings = new ValidationSettings { Depth = ValidationDepth.Spec };
- Enforces absolute URIs in
Coding.system - Required terminology bindings
- Recommended for production API operations
Full
Complete FHIR profile validation:
var settings = new ValidationSettings { Depth = ValidationDepth.Full };
- All Spec checks plus FHIRPath invariants
- Extensible terminology bindings
- Use for compliance testing and profile conformance
What Gets Validated
When you use StructureDefinitionSchemaBuilder, it automatically extracts and creates validation checks from FHIR StructureDefinition metadata. Here's what gets checked:
Tier 1 (Fast) - Universal Checks
These checks run for every CREATE/UPDATE operation:
| Check | Purpose | When Applied |
|---|---|---|
| JsonStructureCheck | Validates JSON is well-formed object with resourceType | Resources only |
| NarrativeCheck | Validates Narrative.status and Narrative.div | Resources only |
| CardinalityCheck | Validates min/max element count (0..1, 1..1, 0.., 1..) | All elements except xhtml |
| TypeCheck | Validates primitive types (id, string, integer, boolean, etc.) | All primitive elements |
Tier 2 (Spec) - Schema-Driven Checks
Additional checks extracted from StructureDefinition metadata:
| Check | Purpose | When Applied |
|---|---|---|
| ReferenceFormatCheck | Validates Reference.reference format (relative/literal/url) | Elements with type=Reference |
| CodingStructureCheck | Validates Coding.system + Coding.code structure | Elements with type=Coding or CodeableConcept |
| ChoiceElementCheck | Validates choice elements (only one variant present) | Elements with name ending in [x] |
| ExtensionStructureCheck | Validates Extension.url is present and value/extension rules | Elements named "extension" |
| FixedValueCheck | Validates element has exact fixed value | Elements with fixedValue constraint |
| PatternCheck | Validates element matches pattern constraint | Elements with patternValue constraint |
| BindingCheck | Validates coded values against built-in, required ValueSets | Elements with binding |
| NestedComplexTypeCheck | Validates nested BackboneElement and complex types | BackboneElement children |
| UnknownPropertyCheck | Rejects unknown/undefined properties | All resources |
| FhirPathInvariantCheck | Validates FHIRPath constraints (ele-1, dom-1, custom invariants) | Elements with constraint definitions |
Tier 3 (Profile) - Slicing, advanced terminology
Profile validation against Implementation Guide profiles declared in
Resource.meta.profile. See the Profile-aware validation
section above for the wiring.
| Check | Purpose | When Applied |
|---|---|---|
| FhirPathInvariantCheck | Validates FHIRPath constraints from IG profiles (e.g. CARIN-BB EOB-inst-careTeam-practitioner) |
Profile elements with constraint definitions |
| BindingCheck | Validates coded values against IG ValueSets (e.g. US Core us-core-birthsex) |
Profile elements with binding (requires ITerminologyService layered with PackageValueSetSource) |
| CardinalityCheck | Enforces tightened cardinality from profile elements (e.g. US Core Patient.identifier min=1) | Profile elements with stricter min/max |
| FixedValueCheck / PatternCheck | Enforces fixed/pattern values from profile elements | Profile elements with fixed/pattern constraints |
Currently unsupported (out of scope): discriminator-based slicing
(e.g. CARIN-BB adjudication-has-amount-type-slice). Slice members in
the snapshot are deduped to the slice header so the validator emits the
correct base cardinality; per-slice constraints are silently ignored.
Tracked for a future iteration.
License
MIT License - see LICENSE file in repository root
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Ensure.That (>= 10.1.0)
- Fhir.Metrics (>= 1.3.1)
- Ignixa.FhirPath (>= 0.5.2)
- Ignixa.Serialization (>= 0.5.2)
- Ignixa.Specification (>= 0.5.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.9)
- Microsoft.IO.RecyclableMemoryStream (>= 3.0.1)
- Superpower (>= 3.1.0)
-
net9.0
- Ensure.That (>= 10.1.0)
- Fhir.Metrics (>= 1.3.1)
- Ignixa.FhirPath (>= 0.5.2)
- Ignixa.Serialization (>= 0.5.2)
- Ignixa.Specification (>= 0.5.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.9)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.9)
- Microsoft.IO.RecyclableMemoryStream (>= 3.0.1)
- Superpower (>= 3.1.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Ignixa.Validation:
| Package | Downloads |
|---|---|
|
Ignixa.DeId
FHIR data de-identification library supporting R4, R4B, R5, R6, and STU3 via Ignixa SDK |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.5.2 | 0 | 6/16/2026 |
| 0.5.0 | 41 | 6/15/2026 |
| 0.0.163 | 276 | 2/11/2026 |
| 0.0.160 | 133 | 2/9/2026 |
| 0.0.155 | 139 | 1/24/2026 |
| 0.0.151 | 127 | 1/21/2026 |
| 0.0.150 | 127 | 1/20/2026 |
| 0.0.149 | 113 | 1/19/2026 |
| 0.0.148 | 120 | 1/18/2026 |
| 0.0.142 | 122 | 1/12/2026 |
| 0.0.137 | 169 | 1/9/2026 |
| 0.0.127 | 163 | 12/29/2025 |
| 0.0.109 | 321 | 12/18/2025 |
| 0.0.101 | 309 | 12/16/2025 |
| 0.0.96 | 450 | 12/10/2025 |
| 0.0.87 | 458 | 12/8/2025 |
| 0.0.70 | 335 | 12/7/2025 |
| 0.0.68 | 260 | 12/7/2025 |
| 0.0.62 | 261 | 12/6/2025 |
| 0.0.59 | 206 | 12/5/2025 |