Expand description
§FHIR R5 for Rust
fhir is a Rust implementation of the HL7 FHIR® Release 5 (R5) data
model, together with a code generator that produces it from the official
FHIR specification JSON files.
Fast Healthcare Interoperability Resources (FHIR) is the HL7 standard for exchanging electronic health records. This crate gives you:
- Every R5 resource (Patient, Observation, Encounter, …) as a Rust
structunderr5::resources, each round-tripping to and from the canonical FHIR JSON viaserde. - Every R5 datatype (Period, HumanName, CodeableConcept, …) under
r5::types, including the primitive newtypes (Code,Id,DateTime, …). - Type-safe code systems — 400+ FHIR
CodeSystems as Rust enums underr5::codes. - A polymorphic
Resourceenum tagged byresourceType, for reading a resource whose type you do not know ahead of time. - Lightweight validation via the
Validatetrait and#[derive(Validate)]. - A code generator under
r5::parsethat reads the FHIR spec JSON shipped inDEFINITIONS_DIRand emits Rust source.
FHIR® is a registered trademark of Health Level Seven International. This crate is not affiliated with or endorsed by HL7.
§Installation
[dependencies]
fhir = "1"
serde_json = "1" # or any other serde data format§Design in one paragraph
Everything in the data model derives serde::Serialize and
serde::Deserialize, so you work with the crate almost entirely through
serde_json. Resources and complex datatypes are plain structs; FHIR
primitive types (code, id, dateTime, …) are thin newtypes such as
Code(String) that serialize transparently to their underlying JSON
value. Optional elements are Option<T>, repeating elements are Vec<T>,
and FHIR’s value[x] choice elements are a generated enum per element. See
Cardinality and choice types below.
§Quick start
Build a Patient, serialize it to canonical FHIR JSON, and parse it back:
use fhir::r5::resources::Patient;
use fhir::r5::coded::Coded;
use fhir::r5::codes::AdministrativeGender;
use fhir::r5::types::{Boolean, HumanName, String as FhirString};
let patient = Patient {
id: Some(FhirString("pat-1".to_string())),
active: Some(Boolean(true)),
gender: Some(Coded::Known(AdministrativeGender::Male)),
name: vec![HumanName {
family: Some(FhirString("Chalmers".to_string())),
given: vec![FhirString("Peter".to_string())],
..Default::default()
}],
..Default::default()
};
// Serialize to canonical FHIR JSON. `None` fields are omitted.
let json = serde_json::to_string_pretty(&patient).unwrap();
assert!(json.contains("\"family\": \"Chalmers\""));
// Parse it back — a perfect round trip.
let parsed: Patient = serde_json::from_str(&json).unwrap();
assert_eq!(parsed, patient);§Primitives are transparent newtypes
A FHIR primitive is a wrapper around a Rust value, so its JSON form is just that value — no wrapper object:
use fhir::r5::types::{Boolean, Code, Integer64};
assert_eq!(serde_json::to_value(Code("final".to_string())).unwrap(), "final");
assert_eq!(serde_json::to_value(Boolean(true)).unwrap(), true);
// `integer64` is serialized as a JSON *string* per the FHIR spec:
assert_eq!(serde_json::to_value(Integer64(9_000_000_000)).unwrap(), "9000000000");§Validation
The Validate trait reports every problem it
finds as a ValidationIssue. Primitive
types check their FHIR regex constraints; #[derive(Validate)] makes
complex types and resources validate recursively, prefixing each nested
issue’s path with the field name.
use fhir::r5::resources::Patient;
use fhir::r5::types::{Id, Uri};
use fhir::r5::validate::Validate;
// Primitive format checks:
assert!(Id("patient-1".to_string()).is_valid());
assert!(!Id("has spaces".to_string()).is_valid());
// Recursive validation of a whole resource:
let mut patient = Patient::default();
assert!(patient.validate().is_empty());
// A `uri` may not be surrounded by whitespace.
patient.implicit_rules = Some(Uri(" http://bad ".to_string()));
let issues = patient.validate();
assert_eq!(issues.len(), 1);
// The path is prefixed with the field name, then the primitive's own label.
assert_eq!(issues[0].path, "implicit_rules.uri");§Code systems as enums
Coded values are available as type-safe enums that serialize to their canonical FHIR code strings:
use fhir::r5::codes::AdministrativeGender;
let gender = AdministrativeGender::Female;
assert_eq!(serde_json::to_value(&gender).unwrap(), "female");
let parsed: AdministrativeGender = serde_json::from_value("male".into()).unwrap();
assert_eq!(parsed, AdministrativeGender::Male);§Reading a resource of unknown type
When you receive JSON but do not know its resourceType, deserialize into
the Resource enum. It is tagged by
resourceType, so serde picks the right variant for you:
use fhir::r5::resources::Resource;
let json = serde_json::json!({
"resourceType": "Patient",
"id": "pat-1",
"active": true
});
match serde_json::from_value(json).unwrap() {
Resource::Patient(patient) => {
assert_eq!(patient.id.unwrap().0, "pat-1");
}
other => panic!("expected a Patient, got {other:?}"),
}§Cardinality and choice types
FHIR element cardinality maps to Rust types as follows:
| FHIR cardinality | Rust type |
|---|---|
0..1 | Option<T> |
1..1 | T |
0..* | Vec<T> |
1..* | Vec1<T> |
A value[x] choice element becomes one generated enum with a variant per
allowed type — for example Observation.value is Option<ObservationValue>
with variants Quantity, String, Boolean, … so exactly one is set.
Required-binding coded fields are their r5::codes enum wrapped in
Coded. Every resource and datatype has a
Type::builder(), and prelude re-exports the common items.
§More examples
Runnable programs live in the examples/ directory. Run one with, e.g.:
cargo run --example build_patient
cargo run --example validate_resource
cargo run --example read_bundle
cargo run --example primitive_extensions
cargo run --example operation_outcome
cargo run --example extensions
cargo run --example transaction_bundle§Crate layout
r5::resources— the 158 R5 resources, plus theResourceenum.r5::types— the ~50 complex datatypes and 21 primitive newtypes.r5::codes— FHIRCodeSystems as enums.r5::validate— theValidatetrait and primitive constraints.r5::meta— per-element specification metadata (cardinality, bindings, choice types, reference targets).r5::parse— the code generator that readsDEFINITIONS_DIR.
Modules§
- client
- An async FHIR REST client (feature
client). An async FHIR REST client (featureclient). - prelude
- Common imports for working with FHIR R5.
- r5
- FHIR Release 5 (R5).
- util
- Utility code for this crate.
Statics§
- DEFINITIONS_
DIR - Absolute path to the directory holding the FHIR R5 specification JSON files that ship with this crate.
Type Aliases§
- Source
Code String - Literate programming: a block of generated Rust source code, as a string.