eio_okta_api/traits/
endpoint.rs

1use std::ops::Deref;
2
3use crate::MapInto;
4use headers::ContentType;
5use http::Version;
6use iri_string::{
7  build::Builder,
8  spec::UriSpec,
9  template::{simple_context::SimpleContext, Context, UriTemplateStr},
10  types::{UriRelativeStr, UriRelativeString},
11};
12
13use crate::query_string::QueryString;
14
15use super::{IntoRequest, Response};
16
17#[derive(Debug, thiserror::Error)]
18pub enum Error {
19  #[error("query string: {0}")]
20  QueryString(#[from] crate::query_string::Error),
21  #[error("template: {0}")]
22  Template(#[from] iri_string::template::Error),
23  #[error("validate: {0}")]
24  Validate(#[from] iri_string::validate::Error),
25}
26
27pub trait Endpoint
28where
29  Self: Sized + IntoRequest + Response + AsRef<<Self as IntoRequest>::Body>,
30{
31  const PATH: &'static str;
32  const VERSION: Version = Version::HTTP_11;
33
34  fn accept(&self) -> ContentType {
35    ContentType::json()
36  }
37
38  fn content_type(&self) -> ContentType {
39    ContentType::json()
40  }
41
42  fn context(&self) -> impl Context {
43    SimpleContext::new()
44  }
45
46  fn query(&self) -> Result<QueryString, Error> {
47    QueryString::simple(&()).map_into()
48  }
49
50  fn path(&self) -> Result<EndpointPath, Error> {
51    EndpointPath::new(self)
52  }
53
54  fn uri(&self) -> Result<UriRelativeString, Error> {
55    let path = self.path()?;
56    let query = self.query()?;
57    let mut uri = Builder::new();
58    uri.path(path.path_str());
59    uri.query(query.as_str());
60    Ok(uri.build::<UriRelativeStr>()?.into())
61  }
62}
63
64#[derive(Debug)]
65pub struct EndpointPath(UriRelativeString);
66
67impl Deref for EndpointPath {
68  type Target = UriRelativeStr;
69  fn deref(&self) -> &Self::Target {
70    self.0.deref()
71  }
72}
73
74impl EndpointPath {
75  fn new<T>(endpoint: &T) -> Result<Self, Error>
76  where
77    T: Endpoint,
78  {
79    let template = UriTemplateStr::new(T::PATH)?;
80    let context = endpoint.context();
81    let expanded = template.expand::<UriSpec, _>(&context)?;
82    let rendered = expanded.to_string();
83
84    let mut uri = Builder::new();
85    uri.path(&rendered);
86    uri.unset_authority();
87    uri.unset_fragment();
88    uri.unset_port();
89    uri.unset_query();
90    uri.unset_scheme();
91    uri.unset_userinfo();
92    uri.normalize();
93
94    Ok(Self(uri.build::<UriRelativeStr>()?.into()))
95  }
96}