Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ async-stream = "0.3.3"
futures-core = "0.3.25"
once_cell = "1.16.0"
reqwest = { version = "0.11.13", features = ["json"] }
reqwest-middleware = "0.2.2"
reqwest-retry = "0.2.2"
serde = { version = "1.0.151", features = ["derive"] }
serde_json = "1.0.91"
time = { version = "0.3.17", features = ["serde", "serde-human-readable"] }
Expand Down
5 changes: 3 additions & 2 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

use std::time::{Duration, SystemTime};

use reqwest::{Method, RequestBuilder, Url};
use reqwest::{Method, Url};
use reqwest_middleware::{ClientWithMiddleware, RequestBuilder};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use tokio::sync::Mutex;
Expand All @@ -38,7 +39,7 @@ const AUTH_VENDOR_PATH: [&str; 2] = ["auth", "vendor"];
/// [`Arc`]: std::sync::Arc
#[derive(Debug)]
pub struct Client {
pub(crate) inner: reqwest::Client,
pub(crate) inner: ClientWithMiddleware,
pub(crate) client_id: String,
pub(crate) secret_key: String,
pub(crate) vendor_endpoint: Url,
Expand Down
2 changes: 2 additions & 0 deletions src/client/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,10 @@ impl Client {
pub async fn create_user(&self, user: &UserRequest<'_>) -> Result<CreatedUser, Error> {
let req = self.build_request(Method::POST, USER_PATH);
let req = req.tenant(user.tenant_id);
println!("{:?}", user);
let req = req.json(user);
let res = self.send_request(req).await?;
println!("{:?}", res);
Ok(res)
}

Expand Down
10 changes: 10 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use std::time::Duration;

use once_cell::sync::Lazy;
use reqwest::Url;
use reqwest_middleware::ClientWithMiddleware;
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};

use crate::Client;

Expand All @@ -37,12 +39,14 @@ pub struct ClientConfig {
/// A builder for a [`Client`].
pub struct ClientBuilder {
vendor_endpoint: Url,
retry_policy: Option<ExponentialBackoff>,
}

impl Default for ClientBuilder {
fn default() -> ClientBuilder {
ClientBuilder {
vendor_endpoint: DEFAULT_VENDOR_ENDPOINT.clone(),
retry_policy: Some(ExponentialBackoff::builder().build_with_max_retries(5)),
}
}
}
Expand All @@ -56,6 +60,12 @@ impl ClientBuilder {
.timeout(Duration::from_secs(60))
.build()
.unwrap();
let inner: ClientWithMiddleware = match self.retry_policy {
Some(policy) => reqwest_middleware::ClientBuilder::new(inner)
.with(RetryTransientMiddleware::new_with_policy(policy))
.build(),
None => reqwest_middleware::ClientBuilder::new(inner).build(),
};
Client {
inner,
client_id: config.client_id,
Expand Down
14 changes: 11 additions & 3 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,17 @@ use reqwest::StatusCode;
#[derive(Debug)]
pub enum Error {
/// An error in the underlying transport.
Transport(reqwest::Error),
Transport(reqwest_middleware::Error),
/// An error returned by the API.
Api(ApiError),
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Transport(e) => write!(f, "frontegg error: transport: {e}"),
Error::Transport(e) => {
write!(f, "frontegg error: transport: {e}")
}
Error::Api(e) => write!(f, "frontegg error: api: {e}"),
}
}
Expand Down Expand Up @@ -61,9 +63,15 @@ impl fmt::Display for ApiError {

impl std::error::Error for ApiError {}

impl From<reqwest_middleware::Error> for Error {
fn from(e: reqwest_middleware::Error) -> Error {
Error::Transport(e)
}
}

impl From<reqwest::Error> for Error {
fn from(e: reqwest::Error) -> Error {
Error::Transport(e)
Error::Transport(reqwest_middleware::Error::from(e))
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use std::fmt;
use std::iter;

use reqwest::RequestBuilder;
use reqwest_middleware::RequestBuilder;
use uuid::Uuid;

pub trait RequestBuilderExt {
Expand Down
16 changes: 13 additions & 3 deletions tests/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use std::collections::HashSet;
use std::env;

// use futures::future::join_all;
use futures::stream::TryStreamExt;
use once_cell::sync::Lazy;
use reqwest::StatusCode;
Expand Down Expand Up @@ -121,6 +122,13 @@ async fn test_tenants_and_users() {
_ => panic!("unexpected response: {tenant_result:?}"),
};

// Used to test retry logic resolving retryable errors such as
// rate limits - maybe
// join_all((0..1000).map(|_| async {
// client.get_tenant(tenants[0].id).await.unwrap();
// }))
// .await;

// Create three users in each tenant.
let mut users = vec![];
for (tenant_idx, tenant) in tenants.iter().enumerate() {
Expand All @@ -139,15 +147,17 @@ async fn test_tenants_and_users() {
.unwrap();

// Verify that the API has roundtripped the key properties.
assert_eq!(created_user.name, name);
// create_user.name is returning an email
// https://github.com/MaterializeInc/rust-frontegg/issues/11
// assert_eq!(created_user.name, name);
assert_eq!(created_user.email, email);

// Verify that fetching the same user by ID from the API returns
// the same properties.
let user = client.get_user(created_user.id).await.unwrap();
assert_eq!(created_user.id, user.id);
assert_eq!(created_user.name, user.name);
assert_eq!(created_user.email, user.email);
assert_eq!(user.name, name);
assert_eq!(user.email, email);
Comment on lines +159 to +160
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely want to make sure the user name is the name we set during create here, rather than the CreateUser object they give us, which is unfortunately wrong at the moment.

assert_eq!(user.tenants.len(), 1);
assert_eq!(user.tenants[0].tenant_id, tenant.id);

Expand Down