Live data from Hacker News

APIs as infrastructure: future-proofing Stripe with versioning

stripe.com

21–30 of 53 posts

Re: APIs as infrastructure: future-proofing Stripe with versioning

#21
post #13

Github also versions their API via headers, but uses the `Accept` header instead: https://developer.github.com/v3/media/

I consider this a misuse of the Accept header. They're defining a bunch of custom media types, which in of itself is pretty weird, but then they're not actually using those media types as the Content-Type of the response. So I can send a request where I say 'Accept: application/vnd.github.full+json', but the response I get back is 'Content-Type: application/json; charset=utf-8', which means the server intentionally handed me a media type that I explicitly said I didn't accept.

I don't understand why they didn't just use the X-GitHub-Media-Type header as a request header.

Re: APIs as infrastructure: future-proofing Stripe with versioning

#22

Does anyone know if there's a publicly-available Ruby gem for doing what's described in this blog post - i.e., cascading transformations with a nice DSL? If someone from Stripe reads this, I think you could count on some decent community interest for this framework if you ever consider open-sourcing it.

It's not a DSL, but take a look at VersionCake.

https://github.com/bwillis/versioncake

"Version Cake is an unobtrusive way to version APIs in your Rails or Rack apps."

Re: APIs as infrastructure: future-proofing Stripe with versioning

#23
post #13

Github also versions their API via headers, but uses the `Accept` header instead: https://developer.github.com/v3/media/

I'm surprised they don't run into CDN issues.

Have run into more than one issue with the vary: Accept being ignored, resulting in everyone getting the result from the first man in regardless of header variance.

Especially noticeable when we tried supporting both JSON and XML via the accepts header, with the version in the mime.

Re: APIs as infrastructure: future-proofing Stripe with versioning

#24
post #15
post #5

This is awesome. As someone who's built many APIs, I have always wondered how Stripe managed all those versions. I knew their code couldn't just be littered with if/thens. This is a really smart way to do it. One question is, over the years, wouldn't you add a lot of overhead to each request in transformation? Or do you have a policy where you expire versions that are more than 2 years old, etc? (skimmed through part…

Assuming that Stripe's userbase grows over time and that their new API versions offer features that are useful to a significant portion of their existing userbase, I would expect the majority of requests at any time to be for a recent API version that needs few (or no) transformations. This is especially likely considering that Stripe provides official client libraries (which are presumably up to date) for a lot of l…

Stripe probably tracks the relative usage of each API version. If they found a lot of their users were stuck on an old version, that would point to a bigger problem than just some per-request overhead.

I'm not sure how true that is. In my experience, integrations with online payment services are mostly write-only code: you do it, you test it, and then no-one goes near it once it's in production unless there's some sort of known bug or security issue.

Literally the last thing I want to do with working, tested code integrating with the service that collects money for a business is make unnecessary changes that might break it. I know several businesses that use versions of APIs that are several years old with services like Stripe, because they have no need to change.

Re: APIs as infrastructure: future-proofing Stripe with versioning

#26

I think this is one area where GraphQL really excels. It essentially can handle all of this versioning for you (as clients specify EXACTLY what they want) - you just need to make sure that as you evolve your schema that existing fields are left as-is and you only add new fields (not an easy task, but no harder than what you have to do in Stripe's protocol).

New fields don't constitute the kind of backwards-incompatible changes mentioned in the blog post (adding fields is just as easy with RESTful APIs). GraphQL does help cut down on payload size (no extra fields for clients that don't need them), but if you're making major changes to the shape of your data, you'll still need to write some kind of compatibility layer.

Re: APIs as infrastructure: future-proofing Stripe with versioning

#27

Always excited to hear Stripe talking about versioning :D For anyone else who's interested, they've written/talked about this a few times over the years, to fill out the picture: - http://amberonrails.com/move-fast-dont-break-your-api/ - https://www.heavybit.com/library/video/move-fast-dont-break-... - https://speakerdeck.com/apistrat/api-versioning-at-stripe - https://brandur.org/api-upgrades - https://news.ycombina…

I built a lot of the new system at Stripe: the old system would set a flag that was globally accessible inside of an API request. This meant that it was impossible to scope down which changes were relevant to which API methods or resources. Now we can statically introspect into changes.

Additionally, devs would need to specify what their changes were independent of where they made the change, which meant that our API reference (which can display warning flags next to changed fields) was missing changes. With the new system we can enforce that the change being made is properly documented, since we know that it's encapsulated inside of the change class itself.

Re: APIs as infrastructure: future-proofing Stripe with versioning

#28
post #21
post #13

Github also versions their API via headers, but uses the `Accept` header instead: https://developer.github.com/v3/media/

I consider this a misuse of the Accept header. They're defining a bunch of custom media types, which in of itself is pretty weird, but then they're not actually using those media types as the Content-Type of the response. So I can send a request where I say 'Accept: application/vnd.github.full+json', but the response I get back is 'Content-Type: application/json; charset=utf-8', which means the server intentionally h…

I disagree, if the response body is a valid application/vnd.github.full+json document, then they sent you what you asked for, they just labeled it differently (but still correctly).

Nothing in the spec says the Accept and Content-Type must match.

Re: APIs as infrastructure: future-proofing Stripe with versioning

#29
From a Stripe developer perspective this sounds like a really clean way to handle API versioning.

From a consumer of Stripe's API's perspective, doesn't this make debugging or modifying legacy code a real pain? Let's say I'm using Stripe.js API's from a few years ago; where do I go to find the docs for that version? Do I need to look at the API change log and work backwards?

Re: APIs as infrastructure: future-proofing Stripe with versioning

#30
post #21

Earlier quoted context omitted.

I consider this a misuse of the Accept header. They're defining a bunch of custom media types, which in of itself is pretty weird, but then they're not actually using those media types as the Content-Type of the response. So I can send a request where I say 'Accept: application/vnd.github.full+json', but the response I get back is 'Content-Type: application/json; charset=utf-8', which means the server intentionally h…

I disagree, if the response body is a valid application/vnd.github.full+json document, then they sent you what you asked for, they just labeled it differently (but still correctly). Nothing in the spec says the Accept and Content-Type must match.

The spec may not mandate that Accept and Content-Type match, but it's still pretty strange. The client is saying "I accept this particular vendor-defined format, with an underlying structure of JSON" and the server says "ok here's a blob of JSON". Nothing in the server's response indicates that the response actually belongs to the specific vendor-defined media type, it could be handing back arbitrary JSON.

I get that from a practical standpoint the server needs to send back a JSON Content-Type, otherwise a lot of clients won't understand that it's JSON and won't decode it properly. But given this, shouldn't they have picked a different header to declare the API version?

What's the benefit of using the Accept header in this fashion? AFAICT there is no benefit at all over just using a custom header.

Post reply on HN