FHIRModels is a Swift library for FHIR® resource data models.
- Native Swift representation of FHIR resources, elements and data types
- Separate targets for DSTU2, STU3, R4 and latest build versions
- Enforced non-nullability of mandatory parameters
- Enums for most closed code systems
- Enums to support value[x] types
- Date/Time parsing, validation and conversion to and from NSDate
- Swift Codable support
FHIRModels works with Swift 5.1 and newer. Running unit tests requires Swift 5.3 and newer.
Swift Package Manager is the recommended way to add FHIRModels to your project:
- In Xcode 11 and newer, go to “File” » “Swift Package Management” » “Add Package Dependency...”
- Search for “FHIRModels” in the panel that comes up or paste the full URL to the GitHub repository, then select the package
- Pick the versioning that best works for you (usually the current version and “up to next major”)
- In order to update the dependency, periodically select “Update to Latest Package Versions” from Xcode 11's “File” » “Swift Package Management” menu
Alternatively, you can add FHIRModels to your Package.swift
file as a dependency:
dependencies: [
.package(url: "https://github.com/apple/FHIRModels.git",
.upToNextMajor(from: "0.2.0"))
]
Assuming you have data that you know represents a FHIR resource, you have two options of instantiating a model. We'll assume you have JSON data for the examples below.
The ResourceProxy
type inspects the resourceType
in the data and instantiates the appropriate class for you:
import ModelsR4
let data = <FHIR JSON data>
let decoder = JSONDecoder()
do {
let proxy = try decoder.decode(ResourceProxy.self, from: data)
let resource = proxy.get()
// `resource` is a generic `Resource`
let patient = proxy.get(if: Patient.self)
// `patient` is a nullable `Patient`
if case .patient(let patient) = proxy {
// `patient` is a `Patient`
}
switch proxy {
case .patient(let patient):
// `patient` is a `Patient`
break
default:
break
}
} catch {
print("Failed to instantiate: \(error)")
}
If you think you know the correct resource type already:
import ModelsR4
let data = <FHIR JSON data>
let decoder = JSONDecoder()
do {
let resource = try decoder.decode(Patient.self, from: data)
} catch {
print("Failed to instantiate Patient: \(error)")
}
To get certain resources from a Bundle
you can do:
import ModelsR4
let data = <FHIR JSON data>
let bundle = try JSONDecoder().decode(ModelsR4.Bundle.self, from: data)
let observations = bundle.entry?.compactMap {
$0.resource?.get(if: ModelsR4.Observation.self)
}
// observations is an array of `Observation` instances
FHIR Resource and Element types are represented as Swift classes,
primitive data types are represented as structs.
All primitives are defined as FHIRPrimitive
,
genericized to the appropriate type such as FHIRBool
or DateTime
.
The library makes extensive use of ExpressibleBy{Type}Literal
so you can take shortcuts when instantiating primitives.
For example, HumanName.given
is an Array of FHIRPrimitive<FHIRString>
that can be instantiated as follows:
import ModelsR4
let name = HumanName(family: "Altick", given: ["Kelly"])
let patient = Patient(name: [name])
name.given?.first // FHIRPrimitive<FHIRString>?
name.given?.first?.value // FHIRString?
name.given?.first?.value?.string // String?
You may be tempted to get the Swift native types from primitive values and pass these around. To get a String from the resource ID you would do:
let id = resource.id?.value?.string
Instead, consider passing the element around in its full form, in this case as FHIRPrimitive<FHIRString>
.
This means you will not lose extensions while you can still use some primitives in code as if they were native types.
With FHIRPrimitive<FHIRString>
for example, you can actually do:
if resource.id == "101" {
}
Conversely, you can also assign many FHIRPrimitive
types with String, Bool or numeric literals, for example:
let patient = Patient(...)
patient.id = "101"
patient.active = true
Lastly, many Swift native types have been extended to offer an asFHIR{type}Primitive()
method. URL and String for example offer:
let url = URL(string: "http://apple.com")!.asFHIRURIPrimitive()
// url is a `FHIRPrimitive<FHIRURI>`
let str = "http://hl7.org/fhir".asFHIRURIPrimitive()
// str is a `FHIRPrimitive<FHIRURI>?`
FHIRModels handles date/time ↔︎ string conversion transparently and will discard invalid dates.
do {
let dateTimeString = "2020-03-12T12:33:54.6543-06:00"
let dateTime = try DateTime(dateTimeString)
dateTime.date.year == 2020
dateTime.time.minute == 33
dateTime.timeZone == TimeZone(secondsFromGMT: -6 * 3600)
} catch {
print("Failed to parse date time string: \(error)")
}
Please feel free to open GitHub issues for questions, suggestions or issues you may have. Because the majority of the codebase is generated we will not be able to accept Pull Requests at this time.
This work is APACHE 2.0 licensed.
FHIR® is the registered trademark of HL7 and is used with the permission of HL7. Use of the FHIR trademark does not constitute endorsement of this product by HL7.