Closed thedodd closed 5 years ago
Yeah! I think there are definitely plans to expose an async interface (we'll be needing it ourselves in a month or two 😆 ). Originally I was waiting for the tokio
/futures
situation to stabilize, but since we've now switched to using reqwest
instead of hyper
, I think we can just begin providing the async client directly (like you've pointed out)-- perhaps via a stripe::async::Client
?
There is a bit of design work to decide how we want to handle traits and apis to support both sync and async in the same crate (my ideal scenario).
It'd probably be nice if a library user could (for example) do both of:
stripe::Customer::create(my_blocking_client, ...)
stripe::Customer::create(my_async_client, ...)
That could be handled by parameterizing all Resource::action
functions to look something like:
impl Customer {
pub fn create<C>(client: &C, params: CustomerParams) -> C::Response<Customer>
where C: RequestSender
{
client.post("/customers", params)
}
}
It would rely on some trait implemented for both stripe::Client
and stripe::async::Client
:
trait RequestSender {
type Response<T>;
pub fn get<T>(&self, path: &str) -> Self::Response<T>
where T: serde::de::DeserializeOwned;
pub fn post<T, F>(&self, path: &str, form: F) -> Self::Response<T>
where T: serde::de::DeserializeOwned,
F: serde::Serialize;
}
impl RequestSender for Client {
type Response<T> = Result<T, Error>;
// ...
}
impl RequestSender for async::Client {
type Response<T> = impl Future<Item=T, Error=Error>; // This may need to be `Box<dyn Future<..>>` or some concrete future instead ¯\_(ツ)_/¯.
// ...
}
A pull request implementing this would definitely be appreciated!
@kestred thanks for the quick response. Yea, I would love to be able to hack on that. For better or for worse, I just implemented a lightweight interface on top of reqwest::async for the items that I needed. Worked out pretty well, but next time I need to touch that code, I'll do my best to take a look at the code here and see if I can put together a PR which satisfies your above description.
At a minimum, I'll ping you for feedback if get a PR up first. If you beat me too it, def ping me. I'm happy to do some code review as well.
@thedodd did you happen to publish your changes with the light async wrapper somewhere? I started down the rabbit hole of converting this lib to use Futures everywhere but I also need just a few API calls at the moment.
@agrinman negative. It is part of one of my closed source projects (part of the DocQL.io infrastructure).
If you have a PR, I’m happy to open a PR against yours with the bits that I need.
Just let me know. I’m pretty time crunched for the next few weeks.
@thedodd / @agrinman - I've implemented an async client in PR https://github.com/wyyerd/stripe-rs/pull/40; a new example in the examples
folder checks that it compiles, but I haven't personally tested it. Should work fine since its just using reqwest
's async behavior...
@kestred awesome, I'll take a look at it when I can. For now I've also just converted the subset I need to be async.
These changes were released in v0.9.0.
To switch to async, in your Cargo.toml use:
stripe-rust = { version = "0.9.0", features = ["async"] }
When creating your client use:
// For older projects
let client = stripe::async::Client::new(); // instead of `stripe::Client`
// For Rust 2018
let client = stripe::r#async::Client::new();
As is the same with other async clients, futures normally need to be run inside a tokio runtime or driven to completion by spawn.
Happy billing :D!
Should this issue be closed? It seems that the async
is indeed on crates.io already.
Sounds good to me.
I would totally use this lib, except that I need an async interface. For now, I've just built a light wrapper around the
reqwest::async::Client
and implemented the logic I need. I would definitely love to get rid of that code and just use this though.Anyway, I've had a lot of success so far with the reqwest async system. Works really well.
Thanks for all the work so far!