Expand description
§FHIR SDK
This is a FHIR library in its early stages. The models are generated from the FHIR StructureDefinitions (see FHIR downloads). It aims to be:
- fully compliant
- as safe as possibe
- as easy to use as possible
- fully featured
§Features
- Generated FHIR codes, types and resources
- Serialization and deserialization to and from JSON
- Optional builders for types and resources
-
Implementation of base traits
- (Base)Resource for accessing common fields
- NamedResource for getting the resource type in const time
- DomainResource for accessing common fields
- IdentifiableResource for all resources with an identifier field
-
Client implementation
- Create, Read, Update, Delete
- Search + Paging
- Batch operations / Transactions
- Authentication callback
- Operations
- Patch
- GraphQL
- FHIRpath implementation
- Resource validation using FHIRpath and regular expressions
§Not Planned
- XML (fhirbolt implements it though)
§Example
use fhir_sdk::r5::resources::Patient;
use fhir_sdk::client::{*, r5::*};
use fhir_sdk::TryStreamExt;
#[tokio::main]
async fn main() -> Result<(), Error> {
// Set up the client using the local test server.
let settings = RequestSettings::default()
.header(header::AUTHORIZATION, "Bearer <token>".parse().unwrap());
let client = Client::builder()
.base_url("http://localhost:8100/fhir/".parse().unwrap())
.request_settings(settings)
.build()?;
// Create a Patient resource using a builder.
let mut patient = Patient::builder().active(false).build().unwrap();
// Push it to the server.
patient.create(&client).await?;
// The id and versionId is updated automatically this way.
assert!(patient.id.is_some());
// Search for all patient with `active` = false, including pagination.
let patients: Vec<Patient> = client
.search(SearchParameters::empty().and(TokenSearch::Standard {
name: "active",
system: None,
code: Some("false"),
not: false,
}))
.try_collect()
.await?;
Ok(())
}
For more examples, see the tests or below.
§Testing
Simply set up the FHIR test environment using cargo xtask docker -- up -d
and then run cargo xtask test
.
If you need sudo to run docker, use the --sudo
or just -s
flag on cargo xtask docker
.
§Known Problems
- The compile time and its memory usage are really high. This is due to the big serde derives being highly generic. It might be possible to shave some off by manually implementing Deserialize and Serialize, but that is complex.
Vec<Option<T>>
is annoying, but sadly is required to allow[null, {...}, null]
for using FHIR resources with extensions..- It is not supported to replace required fields by an extension.
§More examples
§Reading a resource from string/file
use fhir_sdk::r5::resources::Resource;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let resource_str = r#"{
"resourceType": "Patient",
"id": "my-id",
"birthDate": "2024-01-01"
}"#;
let _resource: Resource = serde_json::from_str(resource_str)?;
Ok(())
}
§Authentication callback
use fhir_sdk::r5::resources::Patient;
use fhir_sdk::client::*;
async fn my_auth_callback() -> Result<HeaderValue, eyre::Report> {
Ok(HeaderValue::from_static("Bearer <token>"))
}
#[tokio::main]
async fn main() -> Result<(), Error> {
// Set up the client using the local test server.
let client = Client::builder()
.base_url("http://localhost:8100/fhir/".parse().unwrap())
.auth_callback(my_auth_callback)
.build()?;
// Create a Patient resource using a builder.
let mut patient = Patient::builder().active(false).build().unwrap();
// Push it to the server. On unauthorized failures, the client will call our
// auth_callback method to refresh the authorization.
patient.create(&client).await?;
Ok(())
}
§Resource identifier access
use fhir_sdk::r5::{
codes::AdministrativeGender,
resources::{IdentifiableResource, Patient},
types::{Identifier, HumanName},
};
#[tokio::main]
async fn main() {
// Create a Patient resource using a builder.
let mut patient = Patient::builder()
.active(false)
.identifier(vec![Some(
Identifier::builder()
.system("MySystem".to_owned())
.value("ID".to_owned())
.build()
.unwrap()
)])
.gender(AdministrativeGender::Male)
.name(vec![Some(HumanName::builder().family("Test".to_owned()).build().unwrap())])
.build()
.unwrap();
// Check the identifier value.
assert_eq!(patient.identifier_with_system("MySystem").map(String::as_str), Some("ID"));
}
§License
Licensed under the MIT license. All contributors agree to license under this license.
Modules§
- REST Client Implementation.
- Revision 5 types of FHIR.
- Feature flags
Structs§
- FHIR
base64Binary
type. Wraps binary data and serializes to base64 strings. - Builder errors.
- FHIR instant type: https://hl7.org/fhir/datatypes.html#instant
- FHIR
integer64
type. Wraps an i64, but serializes and deserializes as string. - FHIR time type: https://hl7.org/fhir/datatypes.html#time
- A parsed URL record.
- Wrong resource type for conversion to the specified type.
Enums§
- FHIR date type: https://hl7.org/fhir/datatypes.html#date
- Error that may occur during the String to Date conversion
- FHIR dateTime type: https://hl7.org/fhir/datatypes.html#dateTime
- Parsed parts of a FHIR reference. Can be one of local reference, relative reference or absolute reference. The absolute reference is unchecked and can be anything, it is used as fallback.
Traits§
- A stream of values produced asynchronously.
- An extension trait for
Stream
s that provides a variety of convenient combinator functions. - A convenience for streams that return
Result
values that includes a variety of adapters tailored to such futures. - Adapters specific to
Result
-returning streams