Skip to content

Latest commit

 

History

56 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fhemas

A lightweight, Clojure-native, data-driven FHIR validator.

Based on: https://hl7.org/fhir/validation.html

Philosophy

fhemas is built around the idea of validating FHIR resources directly, without depending on the Java FHIR ecosystem. Given the FHIR resources required for validation (the official FHIR package — StructureDefinitions, ValueSets, etc.), the engine validates any target resource against them.

The library stays data-driven: a custom resource called ValidatorDefinition tells the engine exactly what to extract from a StructureDefinition and which functions to apply to process each field. The engine never guesses — all extraction and compilation behavior is explicit, external configuration, not hardcoded per FHIR version.

Status & Roadmap

fhemas is currently in early active development. See the GitHub Projects board for current progress and planned work.

Validation aspects

  1. Structure
  2. Cardinality
  3. Value Domains
  4. Coding/CodeableConcept bindings
  5. Invariants
  6. Profiles
  7. Questionnaires
  8. Business Rules (explicitly defined by the spec as outside the specification itself)

Scope decisions

  • Questionnaire / QuestionnaireResponse: out of scope for v1. Self- contained sub-validator with its own rules, independent from StructureDefinition-based validation. Not discarded — revisited later.

  • Business Rules (reference resolution, duplicate checks, authorization, etc.): the spec itself lists these as rules "made outside the specification". Treated as an optional, decoupled layer on top of the core engine. Behavior (hard error / warning / skip) is configurable by the implementer.

Configuration philosophy

Per the FHIR spec (validation.html, 7.6.1): full validation, especially terminology, can be computationally expensive, and production use may need to tolerate imperfect data that development environments would reject. Following Postel's law (conservative in what you send, liberal in what you accept), fhemas does not hardcode a single strictness level.

Validation strictness is configurable per pipeline aspect (e.g. Cardinality, Bindings, Invariants), not as a single global on/off switch — a consumer may need Structure to fail hard (security: malicious narrative content) while treating Bindings as a warning (cost: avoids expensive terminology lookups) in the same run.

This configuration is passed via a context map at validation time (not a stateful object) — consistent with fhemas staying data-driven throughout. Sensible defaults are provided so a consumer isn't forced to configure every aspect explicitly; defaults can be overridden granularly.

Exact default values and the full shape of this configuration are still being designed — see the roadmap.

Validation pipeline (build order)

The spec lists validation aspects but does not prescribe an order. The order below was derived by asking, for each aspect: "what must already be resolved for this aspect to be meaningful?" This pipeline order is a fixed responsibility of the engine — it is not something a SchemaProfile declares or a consumer can reconfigure.

  • Hard dependency: aspect B cannot be checked correctly without aspect A having happened first. Reordering breaks correctness.
  • Optimization: aspects are independent of each other, but one runs first because it's cheaper to compute, enabling fail-fast.
Step Aspect Ordering reason
0 Resolve applicable Profile/StructureDefinition Hard dependency — prerequisite for everything else.
1 Structure Hard dependency on step 0.
2 Cardinality Hard dependency on step 0. Runs before Value Domains as an optimization (cheaper, fails fast).
3 Value Domains Hard dependency on step 0. Logically independent from Cardinality.
4 Invariants Hard dependency on step 3. Runs before Bindings as an optimization: FHIRPath evaluation is local computation, while Bindings may require expanding a ValueSet or querying an external terminology server.
5 Bindings (Coding/CodeableConcept) Hard dependency on step 3. Logically independent from Invariants — ordering vs. step 4 is a cost-based optimization, not a correctness requirement.

If ValueSet expansion is fully local and cached, the optimization reason for ordering Invariants before Bindings no longer applies, and both could run in any order — the hard dependencies on step 3 still hold regardless.

Deferred to later phases (not part of the core pipeline above):

  • Profiles (validating rules added by a specific profile, distinct from resolving which profile applies in step 0): layered on top of steps 1–5.
  • Questionnaires: separate sub-validator, out of scope for v1.
  • Business Rules (including reference resolution): optional layer, see Scope decisions above.

Known challenges

  • Element/Extension mutual recursion: Element.extension is of type Extension, and Extension itself extends Element (it also has an .extension field). This is structural self-reference by design in the base FHIR model — almost every element carries an extension field. Since fhemas resolves schemas by looking them up by URL against finite input data (rather than generating compiled code ahead of time), this should not cause the build-time infinite recursion that code-generation approaches need to work around (e.g. via memoized lazy references). Still, this needs to be handled explicitly in the resolution/lookup mechanism — either through reference-by-lookup (not reconstruction) at each recursion level, or an explicit depth guard — to avoid stack overflows on deeply nested extensions. Not yet designed; noted here so it isn't missed when implementing profile/type resolution.

About

A lightweight, Clojure-native FHIR validator.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages