-
-
Notifications
You must be signed in to change notification settings - Fork 130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Codegen revamp #452
Codegen revamp #452
Conversation
Damn! Exciting. I will probably tackle this in a few rounds, starting now! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flushing a few comments. Went for the low handing fruit to get it out of the way. Will come back to the codegen code soon.
examples/endpoints/src/main.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not against structuring like this but what is the motivation here over individual items? Reducing boilerplate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah don't love it but was for boilerplate / feature annoyance. e.g. the Cargo.toml
for this example has
[features]
async = []
runtime-tokio-hyper = ["async-stripe/runtime-tokio-hyper", "async"]
runtime-tokio-hyper-rustls = ["async-stripe/runtime-tokio-hyper-rustls", "async"]
runtime-tokio-hyper-rustls-webpki = ["async-stripe/runtime-tokio-hyper-rustls-webpki", "async"]
runtime-async-std-surf = ["async-stripe/runtime-async-std-surf", "async"]
There are probably cleverer solutions (or could just have the example define a specific runtime), but hoping lots of this can be cleaned up in future when changing client structure allows cleaning up the features.
First lot of comments. Regarding release, Regarding release, I am going to create a new branch off master called |
Last 2 commits update the code generation docs, contributing guide, README, and migration guide. Still very WIP and possibly typo-filled but should make the changes more obvious. |
Last 2 commits make some changes worth nothing:
|
cc @arlyon also happy to fix the merge conflicts if it helps review, but holding off since each change to the generated code on master will gives a fresh merge conflict with the generated files. |
Also 2 more breaking changes I'm curious if any thoughts on:
|
I am on board with those changes also. I have comments that have been piling up but I am waiting to flush them until I have covered more of the code. Stay tuned :) |
Great! No rush - I've been working on a (now mostly functional, but very ugly) One other question I'd like to improve in this PR is any thoughts on overall crate structure. I think instead of having a bunch of separate request crates, it would be nicer to reexport under a single crate so that features (like runtime, or serialization preference) only need to be specified in one place. But that brings up some questions around keeping the crate namespace / feature set clean with so much exposed in that central crate. And whether or not we'd like a single |
No immediate news, however I was experimenting with how to split the clients out: #![feature(impl_trait_in_assoc_type)]
mod headers;
mod request_strategy;
use std::future::{self, Future, Ready};
use futures::FutureExt;
use headers::Headers;
use http_types::{convert::DeserializeOwned, headers::USER_AGENT, Body, Method, Request, Url};
use request_strategy::RequestStrategy;
use stripe_shared::version::VERSION;
use crate::headers::AppInfo;
pub trait Client {
type Response: ClientResponse;
type Fut: Future<Output = Self::Response>;
fn execute(&self, method: http_types::Request) -> Self::Fut;
}
pub trait ClientSync: Client<Fut = Ready<<Self as Client>::Response>> {
fn execute_sync(&self, method: http_types::Request) -> <Self as Client>::Response;
}
impl<P> ClientSync for P
where
P: Client<Fut = Ready<<Self as Client>::Response>>,
{
fn execute_sync(&self, method: http_types::Request) -> <Self as Client>::Response {
self.execute(method).now_or_never().expect("this is always ready")
}
}
trait ClientResponse {
type Ok;
type Err;
fn as_result(self) -> Result<Self::Ok, Self::Err>;
}
impl<T, E> ClientResponse for Result<T, E> {
type Ok = T;
type Err = E;
fn as_result(self) -> Result<<Self as ClientResponse>::Ok, <Self as ClientResponse>::Err> {
self
}
}
struct AsyncClient;
impl AsyncClient {
/// Create a new account with the given secret key.
pub fn new(secret_key: impl Into<String>) -> StripeClient<Self> {
Self::from_url("https://api.stripe.com/", secret_key)
}
/// Create a new account pointed at a specific URL. This is useful for testing.
pub fn from_url<'a>(
url: impl Into<&'a str>,
secret_key: impl Into<String>,
) -> StripeClient<Self> {
StripeClient::from_url(Self, url, secret_key)
}
}
impl Client for AsyncClient {
type Response = Result<http_types::Response, ()>;
type Fut = impl Future<Output = Self::Response>;
fn execute(&self, method: http_types::Request) -> Self::Fut {
async { Err(()) }
}
}
struct BlockingClient;
impl Client for BlockingClient {
type Response = Result<http_types::Response, ()>;
type Fut = Ready<Self::Response>;
fn execute(&self, request: http_types::Request) -> Self::Fut {
future::ready(Err(()))
}
}
impl BlockingClient {
/// Create a new account with the given secret key.
pub fn new(secret_key: impl Into<String>) -> StripeClient<Self> {
Self::from_url("https://api.stripe.com/", secret_key)
}
/// Create a new account pointed at a specific URL. This is useful for testing.
pub fn from_url<'a>(
url: impl Into<&'a str>,
secret_key: impl Into<String>,
) -> StripeClient<Self> {
StripeClient::from_url(Self, url, secret_key)
}
}
struct StripeClient<T: Client> {
client: T,
secret_key: String,
headers: Headers,
strategy: RequestStrategy,
app_info: Option<AppInfo>,
api_base: Url,
api_root: String,
}
impl<C: Client> StripeClient<C> {
pub fn from_url<'a>(client: C, url: impl Into<&'a str>, secret_key: impl Into<String>) -> Self {
StripeClient {
client,
secret_key: secret_key.into(),
headers: Headers {
stripe_version: VERSION,
user_agent: USER_AGENT.to_string(),
client_id: None,
stripe_account: None,
},
strategy: RequestStrategy::Once,
app_info: None,
api_base: Url::parse(url.into()).expect("invalid url"),
api_root: "v1".to_string(),
}
}
}
impl<C: Client> StripeClient<C>
where
C::Response: ClientResponse<Ok = http_types::Response>,
{
pub async fn get(&self, path: &str) -> () {
let resp = self.client.execute(self.get_req(path)).await.as_result();
}
fn get_req(&self, path: &str) -> Request {
let url = self.api_base.join(&format!("{}/{}", self.api_root, path)).expect("invalid url");
let mut req = Request::new(Method::Get, url);
req.set_body(Body::empty());
req
}
}
impl<C: ClientSync> StripeClient<C>
where
C::Response: ClientResponse<Ok = http_types::Response>,
{
pub fn get_sync(&self, path: &str) -> () {
let resp = self.client.execute_sync(self.get_req(path)).as_result();
}
}
#[cfg(test)]
mod test {
use crate::{AsyncClient, BlockingClient, StripeClient};
#[test]
fn sync_example() {
let client = BlockingClient::new("sk_123");
let data = client.get_sync("/test");
}
#[tokio::test]
async fn async_example() {
let client = AsyncClient::new("sk_123");
let data = client.get("/test").await;
}
} Types that only implement the sync client can access the async version, but it returns a future so you won't run into footguns. Clients that implement the async interface can only access the async api. All the common code goes in the 'stripe client whose base client is async' such that the sync clients can access it. No macro rubbish or compile flags. BTW I am very close to saying 'lets merge this into |
Although I will say with the above approach, we will need to swap the execution style from |
Yeah, the more I think about this, the more I think that a sans-io approach makes sense. https://sans-io.readthedocs.io/how-to-sans-io.html Invert the control such that the client is given a request and the types know nothing at all about the client you are using. That way we can provide some clients out of the box but writing your own is trivial (and will reduce another source of recompilation) |
I am thinking we merge this as-is in to a |
I have fast-forwarded the next branch to current master. I am going to rebase this branch, merge it into there, and open a new PR to merge
|
What else is there to fix on |
This Pr as is will probably break things, as will miniserde, as will restructuring the client. I'd like to do all three at once. |
Sorry for the long delay in responding here - should have time to work on this again in a week or so! Please let me know if there's anything I can help with for the branching process / getting this merged into next. |
commit 88d7dbc Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Jan 7 15:00:26 2024 -0500 Use OpenAPI definitions in webhook event definition commit 6adf3f9 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Fri Jan 5 15:01:03 2024 -0800 Remove unnecessary test closure commit c3e3c8f Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Fri Jan 5 12:59:07 2024 -0800 Remove AsRef<str> generated impl for enums commit 8157122 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Thu Dec 28 12:45:11 2023 -0500 Fix polymorphic returned types, add test commit 4b4f493 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Wed Dec 27 15:57:14 2023 -0500 Deduplication WIP commit acc796e Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Tue Dec 26 14:24:59 2023 -0500 Clean update some codegen, start adding back dedup commit e09c203 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Dec 23 15:33:37 2023 -0500 DOC: fix cases of crazy-long lines in doc comments commit 3009c49 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Dec 23 13:59:38 2023 -0500 Try to flatten the namespace as much as possible commit feb13c4 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Dec 23 11:47:48 2023 -0500 Add test for charge having nullable refunds commit d8a2dec Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Dec 23 11:33:51 2023 -0500 List<T> -> Option<List<T>>, no more List<T> defaults commit 3abe2e6 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Fri Dec 22 13:00:18 2023 -0500 Patch URLFinder handling commit 00c139c Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Fri Dec 22 12:04:16 2023 -0500 Reintegrate search pagination too, add lots more pagination testing commit ccb9570 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Dec 17 16:31:39 2023 -0500 Add back AsCursor trait and clean up Expandable removed id method commit 9930853 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Dec 17 16:00:16 2023 -0500 Workaround stripe docs change, don't require doc urls commit b279dcb Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Dec 17 15:53:17 2023 -0500 Keep simple, relegate more generated code to specific generated crates commit 0a4ae20 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Dec 10 14:28:28 2023 -0500 Add initial README changes, migration guide commit 8e2f641 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Dec 10 10:50:47 2023 -0500 Update contributing docs and add codegen readme commit f7a0999 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Dec 3 20:00:16 2023 -0500 [skip ci] Add readme to examples directory commit 11d80e6 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Dec 3 19:41:57 2023 -0500 Clean up some codegen, add ability to autogenerate generated crate description commit a6bba63 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Dec 3 13:10:20 2023 -0500 Make webhook examples more easily runnable without features commit cfb4fd0 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Fri Dec 1 12:59:10 2023 -0500 Address initial comments and fix openapi clippy commit 975440d Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Thu Nov 30 15:16:06 2023 -0500 Add some manual renaming to lessen breaking changes / use clearer names commit 8c04938 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Thu Nov 30 14:52:16 2023 -0500 Remove rustfmt hack for stripe_treasury long lines commit 30eb3c1 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Thu Nov 30 14:48:16 2023 -0500 Try using just path to infer object struct name commit b7630f9 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Thu Nov 30 12:35:03 2023 -0500 Make sure nested paths are also reexported so don't need stripe_types commit c402ad9 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Thu Nov 30 12:04:22 2023 -0500 Allow codegen to replace Default::default() -> None for common option case commit 12db0bc Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 17:57:26 2023 -0500 Add examples back to CI commit 30673e9 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 15:23:29 2023 -0500 Quiet some tracing, make sure nightly formatting present for CI commit 3c817c8 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 15:17:15 2023 -0500 Ci fixups: async-std tests + don't expect out dir to exist commit 9836631 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 15:08:50 2023 -0500 Keep examples separate in ci for now commit 18c4348 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 15:02:39 2023 -0500 Make CI use same indexmap versions commit 168eeda Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 14:59:14 2023 -0500 Try to fix gh actions commit 1f83a15 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 14:24:26 2023 -0500 Add more tests for closable issues commit 0b46685 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 12:40:40 2023 -0500 Make id inference safer and more correct commit 0b958dc Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 11:02:44 2023 -0500 Add some testing commit 1026ea5 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 10:56:16 2023 -0500 Move id handling to external mappings file commit 99d3fa5 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sun Nov 26 00:20:43 2023 -0500 Remove no longer used generated code commit aa9e78c Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Nov 25 20:34:03 2023 -0500 Migrate git workflows commit 6e1b11e Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Nov 25 20:30:07 2023 -0500 Migrate old examples, add back from branch commit 02ba0fa Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Nov 25 17:53:52 2023 -0500 Migrate old tests, add back from branch commit 6ff0bac Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Nov 25 16:58:03 2023 -0500 Add generated files and webhook crate commit 50afbe3 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Nov 25 16:47:14 2023 -0500 Add codegen changes commit edea437 Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Nov 25 13:53:40 2023 -0500 Remove extra files commit 25077cb Author: Matthew Zeitlin <37011898+mzeitlin11@users.noreply.github.com> Date: Sat Nov 25 13:49:41 2023 -0500 Stripe client changes + core types crate More merge changes
88d7dbc
to
9dbe435
Compare
cc @arlyon, rebased and CI is green after a few tweaks! |
Exciting. I am merging this now. |
There is a huge crowd of people excitedly watching from the sidelines 🎉 |
cc @arlyon, sorry for opening a new PR - finally got back to #314 and rebasing onto current master was quite painful. Also tried to leave a cleaner commit history.
I think this is ready for review now. I'll be working on some more changes along the way, primarily documentation for all these changes. One piece I'm not sure how to handle is updating the release workflow to work for the new workspace structure / what the plan is for something like an early RC branch. I would anticipate making more changes, but having an initial RC release would be great at some point so it's more easily dogfooded with real stripe API usage.
TODOS
closes #448, closes #446, closes #442, closes #437, closes #419, closes #417, closes #396, closes #394, closes #389, closes #384, closes #381, closes #352, closes #287, closes #257, closes #246, closes #218, closes #196, closes #154, closes #137
closes #450, closes #411, closes #409, closes #314, closes #283, closes #197, closes #163, closes #456, closes #462, closes #455, closes #461
Future Work