freedom_api/extensions/
mod.rs

1//! # FPS API Extension Traits
2//!
3//! This modules contains a collection of extension traits for the `freedom_models` to enable a
4//! HATEOAS-esque API from within rust.
5//!
6//! These are implemented as traits to allow the `freedom_models` crate to remain extremely thin,
7//! so that when it is ingested by other crates which do not require this functionality, it does
8//! not contribute to the dependency graph.
9
10use std::collections::HashMap;
11
12use freedom_models::{Hateoas, utils::Content};
13
14use crate::{api::Value, error, prelude::Api};
15mod account;
16mod band;
17mod request;
18mod satellite;
19mod site;
20mod task;
21mod user;
22
23pub use {
24    account::AccountExt,
25    band::BandExt,
26    request::TaskRequestExt,
27    satellite::SatelliteExt,
28    site::{SiteConfigurationExt, SiteExt},
29    task::TaskExt,
30    user::UserExt,
31};
32
33fn get_id(reference: &'static str, links: &HashMap<String, url::Url>) -> Result<i32, error::Error> {
34    let url = links
35        .get(reference)
36        .ok_or(error::Error::MissingUri(reference))?;
37
38    let id_str = url
39        .path_segments()
40        .ok_or(error::Error::InvalidUri("Missing Path".into()))?
41        .next_back()
42        .ok_or(error::Error::InvalidId)?;
43
44    id_str.parse().map_err(|_| error::Error::InvalidId)
45}
46
47async fn get_item<T, C>(
48    reference: &'static str,
49    links: &HashMap<String, url::Url>,
50    client: &C,
51) -> Result<T, error::Error>
52where
53    C: Api,
54    T: Value,
55{
56    let uri = links
57        .get(reference)
58        .ok_or(error::Error::MissingUri(reference))?
59        .clone();
60
61    client.get_json_map(uri).await
62}
63
64// TODO: There are BOTH "_embedded" and "content" wrapping maps. However the former contains the
65// links within the map, the later contains the links on the outside of the map. We need to treat
66// these differently.
67async fn get_embedded<T, C>(
68    reference: &'static str,
69    links: &HashMap<String, url::Url>,
70    client: &C,
71) -> Result<<C as Api>::Container<T>, error::Error>
72where
73    C: Api,
74    T: Value,
75{
76    use freedom_models::utils::Embedded;
77
78    let wrapped =
79        get_item::<Embedded<<C as Api>::Container<T>>, C>(reference, links, client).await?;
80
81    Ok(wrapped.items)
82}
83
84async fn get_content<T, C>(
85    reference: &'static str,
86    links: &HashMap<String, url::Url>,
87    client: &C,
88) -> Result<T, error::Error>
89where
90    C: Api + Send,
91    T: Value + Hateoas,
92{
93    let wrapped = get_item::<Content<T>, C>(reference, links, client).await?;
94
95    Ok(wrapped.inner)
96}