13 个重大版本
新 0.14.0 | 2024 年 8 月 18 日 |
---|---|
0.13.0 | 2024 年 7 月 28 日 |
0.12.0 | 2024 年 5 月 26 日 |
0.10.0 | 2024 年 2 月 29 日 |
0.2.0 | 2023 年 3 月 26 日 |
#203 in 网页编程
1,306 每月下载次数
29MB
441K SLoC
FHIR SDK
这是一个处于早期阶段的 FHIR 库。模型是从 FHIR 结构定义生成的(见 FHIR 下载)。目标是
- 完全兼容
- 尽可能安全
- 尽可能易于使用
- 功能齐全
功能
- 生成 FHIR 代码、类型和资源
- 到/从 JSON 的序列化和反序列化
- 类型和资源的可选构建器
- 实现基本特性
- (基础)Resource 用于访问公共字段
- NamedResource 用于在常数时间内获取资源类型
- DomainResource 用于访问公共字段
- IdentifiableResource 用于所有具有标识字段资源
- 客户端实现
- 创建、读取、更新、删除
- 搜索 + 分页
- 批量操作 / 事务
- 操作
- 补丁
- 身份验证
- GraphQL
- FHIRpath 实现
- 使用 FHIRpath 和正则表达式验证资源
未计划
- XML (fhirbolt 实现了它)
示例
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("https://127.0.0.1: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(())
}
更多示例,请参阅 测试 或以下内容。
开发 & 测试
- 安装 cargo-nextest 和 cargo-make:
cargo install cargo-nextest cargo-make
. - 从工作空间根目录,您可以运行以下任务
- 格式化代码:
cargo make format
- 检查格式:
cargo make formatting
- 运行所有 FHIR 版本的 docker 环境:
cargo make docker-ci-up
- 通过 cargo test 运行所有测试:
cargo make test-all
- 使用 cargo nextest 运行所有测试:
cargo make test
- 停止所有 FHIR 版本的 docker 环境:
cargo make docker-ci-down
- 运行 docker 环境,运行所有测试,停止 docker 环境:
cargo make ci-tests
- 运行 clippy 对所有功能集进行检查,任何警告都将失败:
cargo make clippy
- 执行 CI 中进行的所有检查:
cargo make ci
- 运行代码生成器:
cargo make generate
- 格式化代码:
已知问题
- 编译时间和内存使用量都非常高。这是因为大型的 serde derive 非常通用。可能通过手动实现 Deserialize 和 Serialize 来减少一些,但这很复杂。
Vec<Option<T>>
很烦人,但遗憾的是这是必需的,以便使用扩展的 FHIR 资源[null, {...}, null]
。- 不支持用扩展替换必填字段。
更多示例
从字符串/文件中读取资源
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("https://127.0.0.1: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"));
}
最低支持的 Rust 版本
目前,我总是使用最新的 Rust 版本,并没有努力保持 MSRV。如果您需要不同的策略,请提出问题,我可能会考虑更改策略。
许可
在 MIT 许可证下许可。所有贡献者都同意在此许可证下许可。
依赖关系
~1–13MB
~148K SLoC