13 个版本 (6 个重大变更)

0.9.2 2024 年 6 月 18 日
0.9.1 2024 年 6 月 18 日
0.8.0 2024 年 6 月 14 日
0.7.0 2024 年 6 月 7 日
0.3.0 2024 年 5 月 24 日

#1419网页编程

每月 34 次下载

BSD-3-Clause

245KB
5.5K SLoC

XAPI Oxidized

一个用于与 XNAT 网页 API 交互的 RESTful 抽象层库。允许用户通过 Rust 以编程方式对主机进行操作。

目标是能够构建工具和自动化任务。

入门

要在您的项目中使用此库,您必须将其添加到依赖项中。最简单的方法是按照以下操作

$ cargo add oxinat --features core

重要的是要知道必须使用核心功能,因为这可以解锁基本界面。这可能会在未来迭代中更改,但到目前为止,核心仍然作为一个独立的功能。

安装后,您应该能够访问 XnatXnatBuilder 结构,以及 V1V2 -- 这些是初始版本实现的结构,提供了从 XAPI 文档映射的 URI 构建访问权限。

use oxinat::Xnat;

let client = Xnat::configure("your.target.host")
    .use_secure(true)
    .with_username("your-username")
    .with_password("your-password")
    .build()
    .expect_err(); // No version implementation set.

XAPI Oxidized API

版本

一个 Version 是在 core 功能中定义的特质,提供了对 XAPI URI 根组件的访问权限,并且通过实现了 URIBuilder 类型和特质,允许您根据 oxinat 内部系统逐步构建 URI

use oxinat::{Version, ProjectUri};

fn foo<V: Version>(version: &V) -> Result<(), ()> {
    version.project_data().with_id("PROJECT_ID").build()?;
    Ok(())
}

在上面的 .build() 调用中,oxinat 将尝试构建一个类似 Result<String, ..>URI。假设它是有效的,并且上面的情况应该是,从 Result 中解包的结果应该产生类似的内容

"{data_uri}/projects/PROJECT_ID"

{data_uri} 应该已经预先格式化。当通过 Version 的实现使用时,将会调用该类型的 fn data_uri() -> String 方法。如果需要 fn root_uri() -> String,情况也是如此。

自定义版本

在表面层次上,单元 V1V2 已经被实现来访问 UriBuilder 实现的类型和特质。建议简单地使用这些单元,但也可以定义自己的。

为此,您需要安装 derive 特性,然后完整 API 将被解锁并可用。

[dependencies]
oxinat = { version = "0.6.1", features = ["core", "derive"]}

在撰写本文时,建议使用 full 特性并继续使用整个套件。

启用 derive 后,定义自定义的 Version 应该相对简单,有一些要求。您必须调用 #[version()] 在派生类型上方,并至少声明 root_uri 属性。这告诉编译器如何在包含 URI 构建特质之前构建初始的 Version 实现impl。上述 #[version()] 声明具有一些可选的附加属性。

  • data_uri 定义了 fn data_uri() -> String 的值。如果省略,则使用 root_uri
  • legacy 告诉编译器只实现针对旧版 XNAT 系统的子特质。

从版本派生的例子将是

use oxinat::{Version, ProjectUri, ExperimentUri, SubjectUri};

#[derive(Clone, Version, ProjectUri, ExperimentUri, SubjectUri)]
#[version(root_uri = "xapi", data_uri = "data", legacy = true)]
struct MyVersion;

MyVersion
    .project_data()
    .with_id("SOME_PROJECT")
    .subjects()
    .with_subject("SOME_SUBJECT")
    .experiments()
    .build()?

然后生成的 URI 应该看起来像这样

"data/projects/SOME_PROJECT/subjects/SOME_SUBJECT/experiments"

客户端和客户端构建器

拼图中另一个关键部分将是 Xnat<V>XnatBuilder<V>。这些类型允许您代理到/从目标 XNAT 主机的调用。如前所述

use oxinat::Xnat;

use crate::MyVersion;

let client = Xnat::configure("your.target.host")
    .use_secure(true)
    .with_username("your-username")
    .with_password("your-password")
    .with_version(MyVersion)
    .build()
    .expect("must build an XNAT client"); // Should produce a client.

现在,我们设置了所需的版本,以及我们想要的 URI 构建器,我们可以期望有一个合适的 Xnat 客户端。

协议

正在进行一项工作,以预定义一些您可能希望执行的一些常见操作。我们将它们定义为 协议,其中协议与XNAT为授权用户提供资源XNAT的相关 CRUD 操作相关。

对于实现 ClientCoreClientREST 特性的客户端,随着我们继续开发,这些附加特性将可用。

/// Type is able to implement CREATE requests for
/// a particular model. Upon creation, these
/// methods are expected to then return the
/// individual results, and then a
/// `Ok(Self::Model)` response if the request is
/// successful.
trait Create<M> {
    /// Attempt to send a CREATE request to the
    /// XNAT server for **multiple** models.
    fn create_many(&self, models: M) -> Vec<PinnedFuture<'_, M>>;
    /// Attempt to send a CREATE request to the
    /// XNAT server for **one** model.
    fn create_once(&self, model: M) -> anyhow::Result<M>;
}

/// Type is able to implement RETRIEVE requests
/// for a particular model.
trait Retrieve<M> {
    /// Get all instances of a particular model
    /// available to the user via the XNAT host.
    async fn get_all(&self) -> anyhow::Result<Vec<M>>;
    /// Get all instances of a particular model
    /// using another model as the query
    /// parameters for the request.
    async fn get_any_from(&self, model: &M) -> anyhow::Result<Vec<M>>;
    /// Get one instance of a particular model
    /// using another model as the query
    /// parameters for the request.
    async fn get_one_from(&self, model: &M) -> anyhow::Result<M>;
}

/// Type is able to implement UPDATE or UPSERT
/// requests for a particular model.
trait Update<M> {
    /// Attempt to send **multiple** UPDATE
    /// requests to the XNAT host.
    fn update_many(&self, models: M) -> Vec<PinnedFuture<'_, M>>;
    /// Attempt to send **one** UPDATE request to
    /// the XNAT host.
    async fn update_once(&self, model: M) -> anyhow::Result<M>;
}

/// Type is able to implement DELETE requests for
/// a particular model.
trait Delete<M> {
    /// Attempt to send **multiple** DELETE
    /// requests to the XNAT host.
    fn delete_many(&self, models: M) -> Vec<PinnedFuture<'_, M>>;
    /// Attempt to send **one** DELETE request to
    /// the XNAT host.
    async fn delete_once(&self, model: M) -> anyhow::Result<M>;
}

创建

Create 特性已在某些模型的通用 Xnat 客户端上实现。然后,这些模型可用于通过此特性定义的方法来创建以下实例,或针对您的目标XNAT主机。

  • 项目
  • 受试者
  • 实验
  • 扫描
  • 资源

根据每个模型所需的深度,您可能需要提供所有或部分标识符,以便您的目标XNAT主机了解模型应在哪里/如何创建。

例如,在 Scan 模型的案例中,您需要提供项目ID作为 project,受试者标签或ID作为 subject,实验标签或ID作为 experiment,以及指定扫描的ID作为 id

use oxinat::{ClientCore, ClientToken, Xnat};
use oxinat::models::Scan;
use oxinat::protocols::Create;

use crate::{MyVersion, client};

let mut scan = Scan::default();
scan.id = Some(14u64);
scan.experiment = Some("EXPERIMENT_LABEL".into());
scan.subject    = Some("SUBJECT_LABEL".into());
scan.project    = Some("PROJECT_ID".into());

scan = client.create_once(scan).await.expect("scan must be created");

检索

Retrieve 特性已在某些模型的通用 Xnat 客户端上实现。

  • 项目
  • 受试者
  • 实验
  • 扫描
  • 评估者
  • 资源
  • 插件

Retrieve 特性旨在允许您从您的目标XNAT实例中 GET 资源。

use oxinat::{ClientCore, ClientToken, Xnat}
use oxinat::models::Project;
use oxinat::protocols::Retrieve;

use crate::{MyVersion, client};

// Should retrieve all project records from your
// XNAT instance.
let found: Vec<Project> = client.get_all().await.unwrap();

// Should retrieve one project which matches the
// project ID.
let mut project = Project::default();
project.id.clone_from(&Some("SOME_PROJECT_ID".into()));
let found = client.get_one_from(&project).await.unwrap();

当执行查询时,预定义的getter会尝试首先提取相关标识符,然后消耗剩余填充的字段作为查询参数来构造请求路径。

删除

Delete 特性已针对多个模型实现。这允许这些模型用于在您的目标XNAT主机中请求对现有数据的 DELETE 调用。

  • 项目
  • 受试者
  • 实验
  • 扫描
  • 资源

Create 特性类似,为了使 delete 调用成功,您必须提供所有必要标识符,以便进行有效的 DELETE 调用。没有它们,您的XNAT实例将不知道要删除哪些资源,并且作为安全网,oxinat 默认不允许此操作。

依赖关系

~8-19MB
~280K SLoC