#fhir #json #type

fhir-sdk

FHIR 软件开发工具包。用于与 FHIR 接口的库。

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 网页编程

Download history 8/week @ 2024-05-19 148/week @ 2024-05-26 22/week @ 2024-06-02 6/week @ 2024-06-09 3/week @ 2024-06-16 4/week @ 2024-06-23 112/week @ 2024-07-07 320/week @ 2024-07-14 389/week @ 2024-07-21 373/week @ 2024-07-28 100/week @ 2024-08-04 425/week @ 2024-08-11

1,306 每月下载次数

MIT 许可证

29MB
441K SLoC

FHIR SDK

crates.io page docs.rs page license: MIT

这是一个处于早期阶段的 FHIR 库。模型是从 FHIR 结构定义生成的(见 FHIR 下载)。目标是

  • 完全兼容
  • 尽可能安全
  • 尽可能易于使用
  • 功能齐全

功能

  • 生成 FHIR 代码、类型和资源
  • 到/从 JSON 的序列化和反序列化
  • 类型和资源的可选构建器
  • 实现基本特性
    • (基础)Resource 用于访问公共字段
    • NamedResource 用于在常数时间内获取资源类型
    • DomainResource 用于访问公共字段
    • IdentifiableResource 用于所有具有标识字段资源
  • 客户端实现
    • 创建、读取、更新、删除
    • 搜索 + 分页
    • 批量操作 / 事务
    • 操作
    • 补丁
    • 身份验证
    • GraphQL
  • FHIRpath 实现
  • 使用 FHIRpath 和正则表达式验证资源

未计划

示例

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(())
}

更多示例,请参阅 测试 或以下内容。

开发 & 测试

  1. 安装 cargo-nextestcargo-makecargo install cargo-nextest cargo-make.
  2. 从工作空间根目录,您可以运行以下任务
    • 格式化代码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