use email_address_parser::EmailAddress;
use reqwest::blocking::Client;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use url::Url;
pub trait Api {
fn login(&self, email: EmailAddress, password: &str) -> anyhow::Result<LoginResponse>;
}
#[derive(Serialize, Deserialize)]
pub struct LoginRequest {
email: String,
password: String,
}
#[derive(Serialize, Deserialize)]
pub enum LoginResponse {
CreatedAccount { email: String, token: String },
LoggedIn { email: String, token: String },
}
pub struct HttpApi {
client: Client,
base: Url,
}
impl HttpApi {
pub fn new(base: &Url) -> anyhow::Result<Self> {
anyhow::ensure!(base.as_str().ends_with("/"), "API url must end with a /");
Ok(Self {
client: Client::new(),
base: base.clone(),
})
}
fn call_endpoint<I, O>(&self, endpoint: &str, body: I) -> anyhow::Result<O>
where
I: Serialize,
O: DeserializeOwned,
{
Ok(self
.client
.post(self.base.join(endpoint)?)
.json(&body)
.send()?
.json()?)
}
}
impl Api for HttpApi {
fn login(&self, email: EmailAddress, password: &str) -> anyhow::Result<LoginResponse> {
self.call_endpoint(
"login",
LoginRequest {
email: email.to_string(),
password: password.to_string(),
},
)
}
}