-
Notifications
You must be signed in to change notification settings - Fork 3
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
Brainstorming: generate structs, not methods #199
Comments
this sounds good to me, as long as we still generate the docs as well! |
Awesome! Yes, I think this would actually simplify doc generation too. Because our generated docs would show users how to instantiate each endpoint struct. Then our handwritten docs would show users how to use the client and a generated struct to make an API call. |
I think the new openapitor would ideally do a few passes:
By separating the "analyze OpenAPI" phase and the "generate Rust code" phase I think the architecture will be cleaner -- each concern gets a different pass. And we guarantee that we don't start outputting Rust code until we know the OpenAPI schema can be properly analyzed and parsed by us. |
Currently openapitor generates a method for each API endpoint. This method creates a
reqwest::Request
with a body and path/query/fragment taken from the method's parameters, sends it, handles errors, then parses the response into some output type.So, the autogenerated methods need to do a lot of things -- create requests, send them, handle errors, parse responses.
To be clear, the current approach works great. But I'd like to propose a general principle: if we can reduce the amount of autogenerated code without causing programmers to do any boilerplate work when specs change, we should.
I propose an alternative, inspired by cloudflare-rs. In that crate, endpoints are structs, not methods. When a team adds an endpoint, they just add a new struct to the codebase and implement certain traits on it. The core maintainers of cloudflare-rs wrote an API client struct with one "call_api" method which takes any endpoint struct as parameter. The only problem with this approach is that every team has to handwrite the endpoint structs and check they're correct with the API spec. If those endpoint structs were autogenerated instead, there'd be no problem.
So basically, I propose that we (KittyCAD) automate via codegen everything which comes from OpenAPI, and we handwrite the other parts (e.g. the core HTTP, networking, error handling).
This works because the per-endpoint work is the repetitive, always-growing part. Sending/receiving/error-handling the API networking doesn't change when we add new endpoints or change an OpenAPI spec. This reduces the amount of code being generated, which means faster compile times and easier maintenance for KittyCAD engineers, because we've automated the part which changes frequently and handwritten the part that always stays the same.
How would the code-generated Request/Response structs get used by the handwritten client code?
Endpoint
, which is implemented by all the autogenerated structs. Something likeClient
struct which takes anyEndpoint
and can send it.Because the code for sending/receiving/error-handling is defined once and is handwritten, the Rust compiler has less work to do per-endpoint, lowering code generation pressures that result in really slow compile times in crates like async-stripe which also rely on autogenerated methods.
The text was updated successfully, but these errors were encountered: