use http::Uri;
use serde::{Deserialize, Serialize};
use serde_with::{DisplayFromStr, serde_as};
use crate::{Error, Rel};
#[serde_as]
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
pub struct Request {
#[serde_as(as = "DisplayFromStr")]
pub resource: Uri,
pub host: String,
pub rels: Vec<Rel>,
}
impl Request {
pub fn new(resource: Uri) -> Self {
Self {
host: String::new(),
resource,
rels: Vec::new(),
}
}
pub fn builder<U>(uri: U) -> Result<Builder, Error>
where
Uri: TryFrom<U>,
<Uri as TryFrom<U>>::Error: Into<Error>,
{
Builder::new(uri)
}
}
#[derive(Debug)]
pub struct Builder {
request: Request,
}
impl Builder {
pub fn new<U>(uri: U) -> Result<Self, Error>
where
Uri: TryFrom<U>,
<Uri as TryFrom<U>>::Error: Into<Error>,
{
TryFrom::try_from(uri)
.map(|uri| Self {
request: Request::new(uri),
})
.map_err(Into::into)
}
pub fn host<S: Into<String>>(mut self, host: S) -> Self {
self.request.host = host.into();
self
}
pub fn rel<R: Into<Rel>>(mut self, rel: R) -> Self {
self.request.rels.push(rel.into());
self
}
pub fn build(self) -> Request {
self.request
}
}
#[cfg(test)]
mod tests {
use http::Uri;
use super::*;
#[test]
fn example_3_1() {
let resource = "acct:carol@example.com".parse().unwrap();
let rel = Rel::from("http://openid.net/specs/connect/1.0/issuer");
let host = "example.com".parse().unwrap();
let query = Request {
host,
resource,
rels: vec![rel],
};
let uri = Uri::try_from(&query).unwrap();
assert_eq!(
uri.to_string(),
"https://example.com/.well-known/webfinger?resource=acct:carol@example.com&rel=http://openid.net/specs/connect/1.0/issuer",
);
}
#[test]
fn example_3_2() {
let resource = "http://blog.example.com/article/id/314".parse().unwrap();
let query = Request {
host: "blog.example.com".parse().unwrap(),
resource,
rels: vec![],
};
let uri = Uri::try_from(&query).unwrap();
assert_eq!(
uri.to_string(),
"https://blog.example.com/.well-known/webfinger?resource=http://blog.example.com/article/id/314",
);
}
}