eio_okta_api/traits/
endpoint.rs1use 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}