The biggest reason we started working with Stainless was to migrate from the open source generator process we were struggling with, but actually ended up transitioning our hand-rolled Node/JS SDK first because it's both our most popular SDK and because the fragmentation of the JS ecosystem has been a surprisingly big headache[1]. Went into it for reduced maintenance, came out pleasantly surprised at how useful I was finding my own SDK's features around `for...of` on paginated routes, etc.
Congrats on the launch, Stainless crew!
[1] https://www.mux.com/blog/keeping-up-with-the-node-ish-ecosys...
You can see an example of the Go code Stainless produces here: https://github.com/cloudflare/cloudflare-go
(I'm the Stainless founder)
In the end...ongoing maintenance there was still enough of a pain that we made the decision to outsource it. For just one or two SDKs I think we probably would have kept going with it, though.
[1] https://github.com/OpenAPITools/openapi-generator
[2] https://www.mux.com/blog/an-adventure-in-openapi-v3-api-code...
I've spent more of my time than I'd like to admit managing both OpenAPi spec files [1] and fighting with openapi-generator [2] than any sane person should have to. While it's great having the freedom to change the templates an thus generated SDKs you get with using that sort of approach, it's also super time consuming, and when you have a lot of SDKs (we have 6 generated SDKs), in my experience it needs someone devoted to managing the process, staying up with template changes etc.
Excited to see more SDK languages come to Stainless!
[1] https://www.mux.com/blog/an-adventure-in-openapi-v3-api-code...
Here's an example of a typical RESTful endpoint (Lithic's `client.cards.create()`:
https://github.com/lithic-com/lithic-node/blob/36d4a6a70597e...
Here are some example repos produced by Stainless:
1. https://github.com/openai/openai-node 2. https://github.com/openai/openai-python 3. https://github.com/cloudflare/cloudflare-go 4. https://github.com/Modern-Treasury/modern-treasury-java
Some of the language SDKs were dynamic (e.g. Ruby, Python) and could adapt automatically to small API changes like if a new field was added in a response. Some were not (e.g. Java, Go), and for every API change, someone had to manually make the change to that SDK's codebase (add a field, add a struct, add a function for a new endpoint), get it reviewed and merged, and cut a release. As Stripe got bigger and there were API changes all the time, the only way this was even remotely functional was that we had a couple heroic workhorses that'd watch for changes and open hundreds of PRs a year for them. Honestly, in retrospect, it's amazing this even worked.
Getting everything switched over to a generated solution was an arduous process because the new generated code had to be API-compatible with the existing code so that the cutover to generated bindings didn't break every Stripe user under the sun. We eventually got there, but it took a long time.
I like Stainless' mission because after seeing the crazy maintenance hassle that all of this was at Stripe, I think it makes way more sense to save all that engineering time for your more concerns, and outsource this problem to someone else. A plug-and-play way of getting high quality SDKs in all common languages that get pushed to appropriate repositories for distribution and comes with quality companion documentation.
We've actually had pretty good luck at my current job with open source tools like openapi-generator [1], but this sort of codegen is so convoluted that the sustainability of a pure open source solution makes me a little afraid, and you still end up doing a lot of the last mile work yourself.
---
I guess my question is, what is the key differentiator that Stainless offers above just using OpenAPI and its huge library of existing generators?
https://buildwithfern.com/ https://liblab.com/ https://www.speakeasyapi.dev/
Between this and fancy API doc generators (Mintlify, etc.), I feel like we're finally getting close to being able to just go from OpenAPI to Stripe-level "polish".
The amount of runtime code generated per endpoint is typically around 3 short lines – here's an example, also posted elsewhere on this thread: https://github.com/lithic-com/lithic-node/blob/36d4a6a70597e...
I worked on this extensively inside Azure and I know it is not an easy problem (and with more JSON Schema coming in 3.1/4.0, it is only getting harder). There are a lot of API patterns that you want to expose purpose built client abstractions for. Pagination is a big example. If you stick to OpenAPI, you have to ensure your specs use the patterns your client generator recognizes, and it's not always trivial for authors to know how to express that pattern and for your codegen to infer that pattern. In Azure we tended to rely more on custom extensions to OpenAPI because it made the contract a lot clearer and less error prone, but then you lose interoperability.
One thing to consider - I work on TypeSpec[1], and one of the main reasons we built it is to allow encapsulation and reuse of patterns in a first-class way. So, rather than the contract being "endpoints which declare parameters and/or return types with these shapes are inferred to be paginated endpoints", the contract can be "use Page<T>" and the emitted OpenAPI conforms to the contract without effort. It would be fun to see a Stainless TypeSpec library for all the patterns your codegen supports!
Nothing fancy but maybe more helpful than picking through SEO articles in you’re looking for options.
This approach takes minimal effort since we only need to generate Typed DTOs in each language, which all works the same way, where you use the same generic `JsonServiceClient` (created once per language/platform) that use same methods to make API requests making it easy to for our built-in API Explorer [1] (Live Demo [2]) to auto generate API pages for all 11 supported languages which also supports dynamic languages like JS/TS, Python and PHP with additional type hints [3].
[1] https://docs.servicestack.net/api-explorer#code-tab
[2] https://vue-vite-api.jamstacks.net/ui/QueryBookings?tab=code
[3] https://docs.servicestack.net/add-servicestack-reference
Yeah, Stainless is more focused on public SDKs, which can be a lot trickier and more demanding.
Some more details replying to your other comment here: >>40148629
The DTOs are still typed so you still get AutoComplete that also include API Docs and Type hints in the generated DTOs since we full control how DTOs are generated and we're able to capture richer type information in the server C# DTOs (used as blueprints to generate DTOs in different languages).
All the information about how to call the API and what it returns is captured in the Request DTOs, and the only thing the Service Clients need is the BaseUrl for where the APIs are hosted. So you could create a higher level SDK client that just needs to inherit the Service Client and hard code its URL, e.g:
class MyClient : JsonServiceClient(BaseUrl) {}
Where they'll also be able to add any helper methods specific to their APIs (e.g. Custom Auth). For the trade-off of not being able to reuse that client to call different APIs and endpoints, but will still share the same base class so you could still create reusable functionality that can be shared across all Service Clients.
[1] https://docs.servicestack.net/advantages-of-message-based-we...
Is Stainless similar, different?
I resonate with a lot of what is said in the comments. Last mile API tooling is underrated and most companies don't have the deep API platform expertise to build from scratch. The OSS options in the space proved SDK generation could be done but the actual product that you got in hand still needed a lot of work to be enterprise ready. The code was poor quality, wasn't customisable and there was no change management story. We're seeing a new wave of work in this space that's making api platform engineering much more accessible.
The API devex story starts with SDK creation and maintenance but there is a lot more to come!
On the Speakeasy branded classes. We got rid of that some time ago based on customer feedback. Check out our new TS generator https://www.speakeasyapi.dev/post/how-we-built-universal-ts