25 releases
0.5.0-a.2 | Aug 20, 2024 |
---|---|
0.5.0-a.1 | Mar 19, 2024 |
0.4.0 | Mar 12, 2024 |
0.3.4 | Feb 16, 2023 |
0.0.0 | Mar 24, 2022 |
#342 in HTTP client
29 downloads per month
Used in chrs
100KB
2.5K
SLoC
ChRIS Client Library for Rust
lib.rs
:
Client library for ChRIS built on reqwest.
Introduction
ChRIS is a platform for scientific and medical compute. In ChRIS, objects known as ChRIS plugins represent data processing software. A user can run a plugin by creating a plugin instance. Chains of plugin instances are organized as feeds.
Most of the ChRIS API, also known as CUBE, requires a user account. A subset of API endpoints can be accessed anonymously in read-only mode. For example, anyone can list the plugins of a CUBE. However, a user account is required to create plugin instances and browse non-public feeds.
Pro-tip: read the integration test code for code examples.
- https://github.com/FNNDSC/chrs/blob/master/chris/tests/test_public.rs
- https://github.com/FNNDSC/chrs/blob/master/chris/tests/test_logged_in.rs
Authentication
Typically, you start off with a CUBE URL, username, and password. First,
obtain a token with Account::get_token
, then call ChrisClient::build
.
For anonymous access, simply call AnonChrisClient::build
.
Access Modes
All client structs are generic over [Access], being either [RwAccess]
or [RoAccess]. In many cases, methods are only available to an object
when it is of type [RwAccess]. e.g. PluginRw::create_instance
is
defined for the type Plugin<RwAccess>
, however no such method exists
for Plugin<RoAccess>
.
In situations where either [RwAccess] or [RoAccess] works, implement your function to be generic over [Access]. For example,
use chris::{Access, BaseChrisClient, Plugin};
async fn generic_example<A: Access, C: BaseChrisClient<A>>(chris: &C) -> Plugin<A> {
todo!()
}
Types which are generic with [RoAccess] typically have a subset of the methods of the same type but generic with [RwAccess]. If [RoAccess] is good enough for you, consider [EitherClient]:
use chris::{BaseChrisClient, EitherClient, PluginRo};
async fn either_client_example(chris: &EitherClient) -> PluginRo {
chris.plugin().name("pl-dircopy").search().get_only().await.unwrap()
}
It can be convenient to convert objects from T<Access>
to T<RoAccess>
by calling AuthedChrisClient::into_ro, EitherClient::into_ro,
search::Search::into_ro, search::QueryBuilder::into_ro, or LinkedModel::from.
Searching Collections
The ChRIS API is designed around the idea of objects and collections.
For example, the plugin collection API is api/v1/plugins/
, while specific
plugins are retrieved from api/v1/plugins/1/
, api/v1/plugins/2/
, and so on.
Collections usually also have a search API, e.g. api/v1/plugins/search/?name=pl-example
.
Many functions return a search::Search. For example, suppose you want a [Plugin]. You need to search for it like this:
use chris::{Access. BaseChrisClient, Plugin};
async fn get_plugin_example<A: Access, C: BaseChrisClient<A>>(chris: &C) -> Plugin<A> {
chris
.plugin()
.name("pl-example")
.search()
.get_first()
.await
.unwrap()
.expect("plugin not found")
}
You can either use search::Search::get_first
if you want Option<T>
, or
[search::Search::get_only()
] to get just T
.
Response Data, Linked v.s. Unlinked Structs
Structs which represent JSON API response data as-is are defined in
src/models/data.rs
and follow the naming convention *Response
, e.g. [PluginResponse].
These response data structs, in combination with an [Access] and a [request::Client, are
the generic parameters of [LinkedModel]. Specific methods are defined for generic type
combinations. For example, you can get the note of a feed when you have RW access. Hence,
the method FeedRw::note
is defined for [LinkedModel<FeedResponse, RwAccess>
].
In some situations, the API response data contains only a link to the object (e.g.
"https://example.org/api/v1/5/"
instead of the full object (e.g.
{"id": 5, "name": "Example feed", "url": "https://example.org/api/v1/5/", ...}
).
It would be costly to make an additional HTTP GET to create the full [LinkedModel].
Instead, a [LazyLinkedModel] is returned, which works the same as a [LinkedModel] but
is missing the actual object data. The object data can be obtained by calling
LazyLinkedModel::get.
Dependencies
~15–31MB
~529K SLoC