use serde::Serialize;
use url::Url;
use crate::client::{AccountClient, Client, RequestOptions, Response};
use crate::error::Error;
use crate::http::Method;
use crate::operation::Operation;
use crate::security::is_same_origin;
impl Client {
pub async fn get(&self, path: &str) -> Result<Response, Error> {
self.execute(self.raw(Method::GET, path)?).await
}
pub async fn get_with(&self, path: &str, options: &RequestOptions) -> Result<Response, Error> {
self.execute(options.apply(self.raw(Method::GET, path)?))
.await
}
pub async fn post(&self, path: &str, body: &impl Serialize) -> Result<Response, Error> {
self.send_json(Method::POST, path, body, &RequestOptions::default())
.await
}
pub async fn post_with(
&self,
path: &str,
body: &impl Serialize,
options: &RequestOptions,
) -> Result<Response, Error> {
self.send_json(Method::POST, path, body, options).await
}
pub async fn put(&self, path: &str, body: &impl Serialize) -> Result<Response, Error> {
self.send_json(Method::PUT, path, body, &RequestOptions::default())
.await
}
pub async fn put_with(
&self,
path: &str,
body: &impl Serialize,
options: &RequestOptions,
) -> Result<Response, Error> {
self.send_json(Method::PUT, path, body, options).await
}
pub async fn patch(&self, path: &str, body: &impl Serialize) -> Result<Response, Error> {
self.send_json(Method::PATCH, path, body, &RequestOptions::default())
.await
}
pub async fn patch_with(
&self,
path: &str,
body: &impl Serialize,
options: &RequestOptions,
) -> Result<Response, Error> {
self.send_json(Method::PATCH, path, body, options).await
}
pub async fn delete(&self, path: &str) -> Result<Response, Error> {
self.execute(self.raw(Method::DELETE, path)?).await
}
pub async fn delete_with(
&self,
path: &str,
options: &RequestOptions,
) -> Result<Response, Error> {
self.execute(options.apply(self.raw(Method::DELETE, path)?))
.await
}
pub(crate) fn raw(&self, method: Method, path: &str) -> Result<Operation, Error> {
Ok(match self.absolute(path)? {
Some(url) => Operation::at(method, url),
None => Operation::raw(method, path.to_string()),
})
}
fn absolute(&self, path: &str) -> Result<Option<Url>, Error> {
if path.starts_with("https://") || path.starts_with("http://") {
let url = Url::parse(path)?;
if !url.username().is_empty() || url.password().is_some() {
Err(Error::usage(
"URL must not carry credentials; use an access token or a session token",
))
} else if is_same_origin(&url, self.base_url()) {
Ok(Some(url))
} else {
Err(Error::usage(format!(
"URL must be on the Fizzy origin {}, got one on {}",
self.base_url().origin().ascii_serialization(),
url.origin().ascii_serialization()
)))
}
} else {
Ok(None)
}
}
async fn send_json(
&self,
method: Method,
path: &str,
body: &impl Serialize,
options: &RequestOptions,
) -> Result<Response, Error> {
let mut operation = self.raw(method, path)?;
operation.json(body)?;
self.execute(options.apply(operation)).await
}
}
impl AccountClient {
pub async fn get(&self, path: &str) -> Result<Response, Error> {
self.client().get(&self.scoped(path)).await
}
pub async fn get_with(&self, path: &str, options: &RequestOptions) -> Result<Response, Error> {
self.client().get_with(&self.scoped(path), options).await
}
pub async fn post(&self, path: &str, body: &impl Serialize) -> Result<Response, Error> {
self.client().post(&self.scoped(path), body).await
}
pub async fn post_with(
&self,
path: &str,
body: &impl Serialize,
options: &RequestOptions,
) -> Result<Response, Error> {
self.client()
.post_with(&self.scoped(path), body, options)
.await
}
pub async fn put(&self, path: &str, body: &impl Serialize) -> Result<Response, Error> {
self.client().put(&self.scoped(path), body).await
}
pub async fn put_with(
&self,
path: &str,
body: &impl Serialize,
options: &RequestOptions,
) -> Result<Response, Error> {
self.client()
.put_with(&self.scoped(path), body, options)
.await
}
pub async fn patch(&self, path: &str, body: &impl Serialize) -> Result<Response, Error> {
self.client().patch(&self.scoped(path), body).await
}
pub async fn patch_with(
&self,
path: &str,
body: &impl Serialize,
options: &RequestOptions,
) -> Result<Response, Error> {
self.client()
.patch_with(&self.scoped(path), body, options)
.await
}
pub async fn delete(&self, path: &str) -> Result<Response, Error> {
self.client().delete(&self.scoped(path)).await
}
pub async fn delete_with(
&self,
path: &str,
options: &RequestOptions,
) -> Result<Response, Error> {
self.client().delete_with(&self.scoped(path), options).await
}
pub async fn get_all(&self, path: &str) -> Result<Vec<serde_json::Value>, Error> {
self.client().get_all(&self.scoped(path)).await
}
pub async fn get_all_with_limit(
&self,
path: &str,
limit: usize,
) -> Result<Vec<serde_json::Value>, Error> {
self.client()
.get_all_with_limit(&self.scoped(path), limit)
.await
}
fn scoped(&self, path: &str) -> String {
if path.starts_with("https://") || path.starts_with("http://") {
path.to_string()
} else {
format!(
"/{}/{}",
crate::route::encode(self.account_id()),
path.trim_start_matches('/')
)
}
}
}