4 ms·
Stripe V2
- stuartjohnson12 2y ago> The new API is trying to move away from a model where subobjects in an API resource are expanded by default, to one where they need to be requested with an include parameter. We had plenty of discussions about this before I left. This feels like the worst middleground between REST and GraphQL. All of the data flexibility of GraphQL with the static schemas of REST. Wasn't this kind of thing the whole idea underpinning GraphQL? Maybe you can get around this with new SDK generators handling type safety for you, but I am definitely not looking forward to trying to understand the incomprehensible 5 layers of nested generics needed to make that work. I remember looking up to Stripe as pioneers of developer experience. This reads like a PM with their back against the wall with a mandate from above (make requests n% faster) rather than a developer-first design choice made to help people build better systems.
- echelon 2y agoMy team did this at Square too. When you give everyone a grab bag of everything without asking them what they need, it takes longer to materialize the other entities from other caches and systems, especially in bulk APIs. Most of your callers don't even need or read this data. It's just there, and because you don't know who needs what, you can never remove it or migrate away. By requiring the caller to tell you what it wants, you gain an upper hand. You can throttle callers that request everything, and it gives you an elegant and graceful way to migrate the systems under the hood without impacting the SLA for all callers. You also learn which callers are using which data and can have independent conversations, migrations, and recommendations for them. Each sub-entity type being requested probably has a whole host of other systems maintaining that data, and so you're likely dealing with active-active writes across service boundaries, cache replication and invalidation, service calls, and a lot of other complexity that the caller will never see. You don't want the entire universe of this in every request. It's a nightmare to have everything in the line of every request for simply legacy reasons. If you have to return lots of sub-entities for everyone all the time, you're more likely to have outages when subsystems fail, thundering herd problems when trying to recover because more systems are involved, and longer engineering timelines due to added complexity of keeping everything spinning together. By making the caller tell you what they need, you quantitatively know which systems are the biggest risk and impact for migrations. This moves the world into a more maintainable state with better downstream ownership. Every request semantically matches what the caller actually wants, and it hits the directly responsible teams. Stripe might also be dealing with a lot of legacy migrations internally, so this might have also been motivated as they move to a better internal state of the world. Each sub-entity type might be getting new ownership. Grab bag APIs are hell for the teams that maintain them. And though the callers don't know it, they're bad for them too.
- airstrike 2y agoSounds like boring code with lots of plumbing scores yet another point against magically flexible code claiming to handwave away complexity
- echelon 2y ago> against magically flexible code claiming to handwave away complexity It might have just been scope creep over time that became a mountain of internal technical debt, data dependencies, and complexity. That's difficult to cleanly migrate away from because you can't risk breaking your callers. That's what it was in our case.
- eYrKEC2 2y agoI think it's the flexible middle-ground that REST APIs and GraphQL APIs converge on. GraphQL APIs that are completely open are trivially DOS'd with recursive data loops or deeply nested over-fetching requests and hence need to be restricted down to acceptable shapes -- thus converging on essentially the same solution from the opposite direction when constructing a GraphQL API.
- dartos 2y ago> trivially DOS'd with recursive data loops or deeply nested over-fetching requests The depth of recursion can be limited in servers like Apollo. Maybe “trivally easy to misconfigure”
- eYrKEC2 2y agoYeah. First you limit the depth of recursion. Then you limit which objects can nest which other objects, under which circumstances.. Pretty soon -- you have a proscribed set of shapes that you allow... and you've converged on the same solution as achieved in the other direction by the REST API requiring explicit data shape inclusion from the caller.
- dartos 2y agoThat’s a slippery slope that I don’t think holds up. When designing the schema, you keep performance and security in mind. You need to do the same for REST APIs. Just because some nodes don’t have edges that connect to some other nodes does not mean you’re back at REST. The main benefit of graphql in not creating super rigid contracts between the frontend and the backend or between services is maintained.
- tshaddox 2y ago> and you've converged on the same solution as achieved in the other direction by the REST API requiring explicit data shape inclusion from the caller. Yes, and with GraphQL you didn't have to invent your own way to represent the syntax and semantics in the query string, and you get to use the GraphQL type system and tooling.
- rcaught 2y ago> These days a great SDK, not a great API, is a hallmark, and maybe even a necessity, of a world class development experience. IMO, you can't build a great SDK without a great API. Duct tape only goes so far.
- resonious 2y agoI agree with you. I actually don't see any value-add from SDKs that wrap HTTP requests. HTTP is a standard, and my programming environment already provides a way to make requests. In fact it probably provides multiple, and your SDK might use a different one from what I do in the project, resulting in bloat. And for what gain? I still need to look at docs and try my best to do what the docs are telling me to. Now if it's a statically typed language then I kinda get it. Better IDE/lsp integration and all. But even then, just publish an OpenAPI spec and let me generate my own client that's more idiomatic with my project.
- skydhash 2y agoThis is one of the sentiment that powers the Common Lisp ecosystem. There's already good data structures and functions in the standard (and quasi standard) library, why do you need to invent new ones? In other languages (Node JS), you take a library and it brings a whole kitchen with it.
- buremba 2y agoI like the middle ground where I generate the models from OpenAPI but stick to my preferred HTTP library of choice in the language I’m using.
- in-pursuit 2y agoI agree with the sentiment that great APIs are a prerequisite to great SDKs, but great SDKs are really about time saving. Consider AWS's API, which requires a specific signing mechanism. That is annoying to implement manually. In general, the common method of shared-secret passed via bearer token is pretty insecure. I hope to see that change over time, and SDKs can help facilitate that.
- 2y ago
- efilife 2y ago> Few of us want to be making manual HTTP calls out to APIs anymore. What's the other way?
- jsnell 2y ago> There was a time not too long ago when Stripe cutting a new API version would’ve been a major event in the tech world, but in three months I didn’t come across a single person who mentioned it. I don't think it would have been a major event, ever. Few people care about a API version bump in the abstract. It'll mostly be big news if it's bad news somehow (user-visible feature regressions, access restrictions, etc) or if there's some significant new features. This appears to be neither. It's just inconsequential re-arranging of the living room furniture for better feng shui.
- quantumwoke 2y agoReminiscent of the changes to the Microsoft Graph API, which personally I wasn't a fan of. Hope stripe can maintain its developer first mentality.
- deleted 2y ago[deleted]
- aftbit 2y ago>That’s got to be true too. Few of us want to be making manual HTTP calls out to APIs anymore. These days a great SDK, not a great API, is a hallmark, and maybe even a necessity, of a world class development experience. I may be in that "few of us" set because I really prefer a simple HTTP API that I can implement myself rather than having to take a library dependency on some code with transitive dependencies and unknown future maintainership. A good SDK is nice to have but a integrating with a bad one by accident is horrible.
- deleted 2y ago[deleted]
- rglover 2y ago> Few of us want to be making manual HTTP calls out to APIs anymore. These days a great SDK, not a great API, is a hallmark, and maybe even a necessity, of a world class development experience. I'm of the opposite mind. A simple API that I can just call with Fetch is far better than having to learn most SDKs. Stripe's Node.js SDK is fairly clean/without headaches, but I look at stuff like the AWS JS SDK and want to gouge my eyes out. At least with an HTTP API, there's some modicum of standardization. SDKs are and will always be the wild west. The only exception with this that I see frequently is authentication. Some are simple Authorization headers w/ a Bearer <Token>, others (like PayPal the last time I implemented it) require an undocumented base64 encoding of the token.
- HatchedLake721 2y ago100%. Great API is a must have, great SDK is nice to have. In my case SDK is an unnecessary abstraction. I wrote 50+ SaaS app integrations from scratch and the last thing I want to do is bring over 50 dependencies rather than make simple HTTP requests.
- MarcelOlsz 2y agoAlmost every time I use an SDK I get burned. Happened for firebase, github, and a few others. Same with ORM's.
- noitpmeder 2y agoIn what regard? The SDKs change out from underneath you?
- edoceo 2y agoNot OP but yep. Forced SDK upgrade, dependency chain and vendor driven churn. But, eg, Twilio been using the same HTTP methods for like 10 years. Many other SDK based interfaces (not necessarily Stripe) have forced that churn.
- noitpmeder 2y ago
- HatchedLake721 2y agoStrange that https://jsonapi.org/examples/ https://jsonapi.org/examples/ never went into the masses, I suspect because it came out around the same time as GraphQL. For me it’s the perfect mix between doing REST from scratch and GraphQL. And it comes with the similar include and expand pattern that Stripe v2 introduced.
- adsteel_ 2y agoMy experience with JSON API is that it doesn't come with the out-of-box tooling that GraphQL comes with. GraphQL is declarative enough that just writing the queries, mutations, and types gives you UI documentation and a GraphiQL playground. I still prefer the simplicity of a REST API, but GraphQL is clearly winning on the tooling front.
- stnderror 2y agoThere are a couple of changes more that arguably made the API worse: * Event payloads changed to be “thin events” * List endpoints became only eventually consistent They also took away the “expand” parameter, which seems more useful that the new “include” one that works in some endpoints. Generally their API design seems much more confusing and inconsistent nowadays. But to be fair their API is much bigger too. I guess it is hard to keep the same quality when you have so many engineers working on it.
- rattray 2y agoEventually consistent list endpoints!? How did they justify/explain that? Do they provide guidance on how to work around it?
- rattray 2y ago> a new API version also presents an opportunity to clear out blemishes, and I expected to see more of that Curious, what are some other Stripe API blemishes that folks would have liked to see cleaned up in a v2?
- yasserf 2y agoI feel that with typescript you can sort of build an SDK by creating a thin wrapper around fetch and have it consume the API types as a generic. This way you still have the benefits of type safety without the bloat of creating an actual SDK. SDKs tend to be useful when they hold state / don’t just proxy to a rest call, but I don’t see why we need wrapper libraries. They also hide away the complexity of knowing how the rest api is meant to consume data (query / params / body / encoding). So the assumption is the rest API itself makes sense. I took this approach with a backend typescript framework called vramework.dev which can generate openapi specs as well as the thin fetch wrapper, and feel like for my projects satisfies my needs.
- lonelygiraffe 2y agoIf you use APIs make sure you don’t break them: https://github.com/Tufin/oasdiff https://github.com/Tufin/oasdiff