> 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.
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.
> 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.
I 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.
Don't most production-ready GraphQL servers have some sort of static query cost estimator that is intended to be hooked up to a rate limiter? At the bare minimum, it should be very easy to set up simple breadth+depth limits per request.
This doesn't seem meaningfully more complex than rate limiting a REST API, especially a REST API with configurable "includes."
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.
> 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.
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.