use crate::types::{Gender, Nationality, RandomUser, RandomUserResponse, RandomUserResult};
use thiserror::Error;
pub struct UserGeneratorBuilder {
req: reqwest::RequestBuilder,
}
impl UserGeneratorBuilder {
pub(crate) fn new(req: reqwest::RequestBuilder) -> Self {
Self { req }
}
pub fn gender(self, gender: Gender) -> Self {
Self::new(
self.req
.query(&[("gender", serde_json::to_value(gender).unwrap().as_str())]),
)
}
pub fn nationality(self, nationality: Nationality) -> Self {
Self::new(
self.req
.query(&[("nat", serde_json::to_value(nationality).unwrap().as_str())]),
)
}
pub fn nationalities(self, nationalities: &[Nationality]) -> Self {
let mut nats = String::new();
for nat in nationalities {
nats += serde_json::to_value(nat).unwrap().as_str().unwrap();
nats.push(',');
}
nats.pop();
Self::new(self.req.query(&[("nat", nats)]))
}
pub fn seed(self, seed: &str) -> Self {
Self::new(self.req.query(&[("seed", seed)]))
}
pub fn password(self, charset: &str) -> Self {
Self::new(self.req.query(&[("password", charset)]))
}
pub async fn fetch_with_info(self, count: usize) -> Result<RandomUserResult> {
self.count(count).request().await
}
pub async fn fetch(self, count: usize) -> Result<Vec<RandomUser>> {
Ok(self.count(count).request().await?.results)
}
pub async fn fetch_one(self) -> Result<RandomUser> {
Ok(self.fetch(1).await?.remove(0))
}
fn count(self, count: usize) -> Self {
Self::new(self.req.query(&[("results", count)]))
}
async fn request(self) -> Result<RandomUserResult> {
let api_rsp = self.req.send().await?;
let rsp = Self::parse_response(api_rsp).await?;
match rsp {
RandomUserResponse::Error(e) => Err(RandomUserError::Api(e)),
RandomUserResponse::Result(res) => Ok(res),
}
}
async fn parse_response(response: reqwest::Response) -> Result<RandomUserResponse> {
let content_type = response
.headers()
.get("content-type")
.ok_or(RandomUserError::BadFormat)?
.to_str()
.map_err(|_| RandomUserError::BadFormat)?
.to_owned();
let text = response.text().await?;
match content_type {
ct if ct.contains("text/plain") => Ok(RandomUserResponse::Error(text)),
ct if ct.contains("application/json") => {
serde_json::from_str::<RandomUserResponse>(&text)
.map_err(|_| RandomUserError::BadFormat)
}
_ => Err(RandomUserError::BadFormat),
}
}
}
pub struct UserGenerator {
client: reqwest::Client,
}
impl UserGenerator {
const API_URL: &str = "https://randomuser.me/api/1.4/";
#[must_use]
pub fn new() -> UserGenerator {
UserGenerator {
client: reqwest::Client::new(),
}
}
#[must_use]
pub fn get(&self) -> UserGeneratorBuilder {
UserGeneratorBuilder::new(self.client.get(Self::API_URL))
}
pub async fn fetch_with_info(&self, count: usize) -> Result<RandomUserResult> {
self.get().fetch_with_info(count).await
}
pub async fn fetch(&self, count: usize) -> Result<Vec<RandomUser>> {
self.get().fetch(count).await
}
pub async fn fetch_one(&self) -> Result<RandomUser> {
self.get().fetch_one().await
}
}
impl Default for UserGenerator {
fn default() -> Self {
Self::new()
}
}
type Result<T> = std::result::Result<T, RandomUserError>;
#[derive(Debug, Error)]
pub enum RandomUserError {
#[error("Reqwest error: {0}")]
Reqwest(#[from] reqwest::Error),
#[error("Api error: {0}")]
Api(String),
#[error("Bad format")]
BadFormat,
}