Crates.io | fhir-sdk |
lib.rs | fhir-sdk |
version | 0.14.1 |
source | src |
created_at | 2023-03-24 18:37:28.650828 |
updated_at | 2024-08-25 14:29:09.035418 |
description | FHIR Software Development Kit. Library for interfacing with FHIR. |
homepage | https://github.com/FlixCoder/fhir-sdk |
repository | https://github.com/FlixCoder/fhir-sdk |
max_upload_size | |
id | 819612 |
size | 169,008 |
This is a FHIR library in its early stages. The models are generated from the FHIR StructureDefinitions (see FHIR downloads). It aims to be:
use fhir_sdk::r5::resources::Patient;
use fhir_sdk::client::{*, r5::*};
use fhir_sdk::{TryStreamExt, header};
#[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,
}))
.await?
.all_matches()
.try_collect()
.await?;
Ok(())
}
For more examples, see the tests or below.
cargo install cargo-nextest cargo-make
.cargo make format
cargo make formatting
cargo make docker-ci-up
cargo make test-all
cargo make test
cargo make docker-ci-down
cargo make ci-tests
cargo make clippy
cargo make ci
cargo make generate
Vec<Option<T>>
is annoying, but sadly is required to allow [null, {...}, null]
for using FHIR resources with extensions..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(())
}
use fhir_sdk::r5::resources::Patient;
use fhir_sdk::client::*;
use fhir_sdk::{HttpClient, HeaderValue};
/// Gets called whenever there is an UNAUTHORIZED response.
/// Retries the response with the new Authorization header.
async fn my_auth_callback(client: HttpClient) -> Result<HeaderValue, anyhow::Error> {
let _response = client.get("my-url").send().await?;
Ok(HeaderValue::from_static("Bearer <token>"))
}
/// Same as above, but with state.
struct MyLogin {
valid: std::time::Instant,
}
impl LoginManager for MyLogin {
type Error = anyhow::Error;
async fn authenticate(&mut self, client: HttpClient) -> Result<HeaderValue, Self::Error> {
if self.valid.elapsed().as_secs() > 360 {
let _response = client.get("my-url").send().await?;
self.valid = std::time::Instant::now();
}
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())
// Register async fn as callback.
.auth_callback(my_auth_callback)
// Register struct with state. Overwrites previous callback.
.auth_callback(MyLogin { valid: std::time::Instant::now() })
// Register async closure. Overwrites previous callback.
.auth_callback(|_client: HttpClient| async move { anyhow::Ok(HeaderValue::from_static("hi")) })
.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(())
}
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"));
}
Currently, I am always using the latest Rust version and do not put in any effort to keep the MSRV. Please open an issue in case you need a different policy, I might consider changing the policy.
Licensed under the MIT license. All contributors agree to license under this license.