oxinat 0.6.2

XNAT REST API client
Documentation
# XAPI Oxidized #
A RESTful abstraction layer library for interacting with XNAT web
APIs. Allows the user to perform actions against a host
programmatically via Rust.

The intent is to be able to build tools and automated tasking.

## Getting started ##
To use this library in your project, you must add it to your
dependencies. The easiest way to do this is by simply doing the
following:

```bash
$ cargo add oxinat --features core
```

It is important to know that the core feature must be utilized as this
unlocks the basic interface. This may be changed in future iterations,
but for now the core stays as a separate feature.

Once installed, you should have access to structs `Xnat` and
`XnatBuilder`, as well as `V1` and `V2`-- the initial version
implemented structs granting access to building URIs mapped from
XAPI documentation.

```rust
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 ##

### Versions ###
A `Version` is a trait defined in the `core` feature, granting access
to the root component of **XAPI** **URI**s, and with `URIBuilder`
implemented types and traits, allows you to construct **URI**s in a
progressional manner guided by the `oxinat` internal system.

```rust
use oxinat::{Version, ProjectUri};

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

At the above `.build()` call, `oxinat` will try to build a **URI** in
the form of a `Result<String, ..>`. Assuming it is valid, and the
above case should be, the resulting string from unwrapping the the
`Result` should produce something like:

```rust
"{data_uri}/projects/PROJECT_ID"
```

`{data_uri}` should be already pre-formatted. When utilized through
an implementation of `Version`, a call will be made to the type's
`fn data_uri() -> String` method. This will also be true in the case
where `fn root_uri() -> String` is required.

### Custom Versions ###
At the surface level, the units `V1` and `V2` have already been
implemented to access `UriBuilder` implemented types and traits. It
would be recommended to simply use these units, but it is possible
to define your own.

To do this, you will need to install the `derive` feature, but then
after the full API will be unlocked and available.

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

At the time of writing, it would be advisable to instead use the
`full` feature and still make use of the entire suite.

With `derive` enabled, defining a custom `Version` should be
relatively easy with some requirements. You must make a call to
`#[version()]` above the deriving type along with at least declaring
the `root_uri` attribute. This tells the compiler how to construct
the initial `Version` impl, prior to inclusion of **URI** building
traits. Said `#[version()]` declaration comes with a few
additional attributes that are optional.

- `data_uri` defines the value of `fn data_uri() -> String`.
`root_uri` is used instead if omitted.
- `legacy` tells the compiler to only implement sub-traits for legacy
XNAT systems.

An example of deriving from a version would be:

```rust
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()?
```

And then the resulting **URI** should look something like this:
```rust
"data/projects/SOME_PROJECT/subjects/SOME_SUBJECT/experiments"
```

### Clients and  Client Builders ###
Another key piece to the puzzle is going to be `Xnat<V>` and
`XnatBuilder<V>`. Where these types allow you to broker calls to
to/from a target XNAT host. As described earlier:

```rust
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.
```

Where now, we are setting the desired version, with the **URI**
builders we want, we can expect to have a proper `Xnat` client.