20 ms·
Enabling the Future of GitHub's REST API with API Versioning
- garblegarble 4y agoIt's not awfully promising that the article talks about "X-GitHub-Api-Version" and then calls it "X-GitHub-Version" later on... Edit: it's been fixed now, good Github doc fix response time!
- pkulak 4y agoI thought the days of prefacing vendor headers with "X-" were long over.
- sdiacom 4y agoEspecially if you're already prefixing it with "GitHub-". Like, you're definitely not going to step over the HTTP standard headers any time soon. That said, the overall concept is deprecated: https://www.rfc-editor.org/rfc/rfc6648 https://www.rfc-editor.org/rfc/rfc6648
- timrogers 4y agoAuthor here. We just wanted to be consistent here with other GitHub-specific headers prefixed this way. We could have had different headers with different formats or tried to change the formats of the old headers, but we figured this was the sanest way.
- leipert 4y agoHow would you do that breaking change then? (slightly in jest ;))
- Gigachad 4y agoThe reason for that was eventually these headers became real standards and software would break when the X was removed. I very much doubt we will ever see github api headers added in to nginx and apache. So if your header is something you think should/will be standard but it's still in beta/testing, give it the real name.
- timrogers 4y agoAuthor here! Thank you so much for flagging this - it’s amazing what can sneak through so many proof reading attempts. We’ll get this fixed.
- Too 4y agoThis should be argument enough that /v2 is a lot less susceptible to such error. Please also return error if the wrong key was used, instead of silent fallback of assuming no version.
- andrewfromx 4y agointeresting. No more /api/v1 or /api/v2 in the urls. Now it's just /api/thing but pass in X-Api-Version in header and the version is a date not a number or 1.2.3 three numbers.
- dottedmag 4y agoThe difference is purely cosmetic: version could have been stuffed into URL as /api/2022-11-28 and nothing would change.
- CharlieDigital 4y agoIt's much more ergonomic and compact to use as an end user than a dedicated header, IMO.
- dottedmag 4y agoAgreed, pragmatically a separate header is a dubious choice. Semantically it is equivalent though.
- chrismeller 4y agoI also found it odd that they switched from URL versioning to an HTTP header. Sure if I’m writing an integration that’s no big deal, but it makes it more of a PITA to do things from the CLI with curl.
- datapolitical 4y agoWell, you don’t need the header
- chrismeller 4y agoYou don’t need it if you’re expecting the current 2022-11-28 version, but it seems like you’ll need it to “opt-in” to any future ones, which presumably includes new endpoints that don’t even exist in the current.
- CharlieDigital 4y agoArticle says that it doesn't apply to the GQL API. Wonder what this means long term for the GQL interface.
- timrogers 4y agoAuthor here! We still love our GraphQL API, and REST and GraphQL continue to evolve in parallel. We’re just aware that GraphQL is pretty different, so if we want versioning there, we’ll need to tackle it differently. (On top of that, GraphQL has some nice primitives that come for free, like deprecated fields.)
- the_mitsuhiko 4y agoWould be curious to hear though how GitHub plans to evolve the GraphQL API. From the recent almost unannounced removal of the GraphQL package API one can get the impression that it’s safer to use the REST APIs.
- swyx 4y ago> recent almost unannounced removal of the GraphQL package API i missed this, is there a canonical source to learn more?
- timrogers 4y agoAuthor here! Here's the link to that announcement: https://github.blog/changelog/2022-08-18-deprecation-notice-graphql-for-packages/ https://github.blog/changelog/2022-08-18-deprecation-notice-...
- timrogers 4y agoAuthor here! At the moment, we allow teams across GitHub to make their own decisions on REST vs. GraphQL. Some teams are investing heavily in GraphQL (e.g. for the new GitHub Projects), whereas others are opting for REST. That said, we do want to firm up our guidance internally and communicate more clearly to the world how we think about REST and GraphQL.
- j0057 4y agoIf you don't specify a version, the default will be the 2022-11-28 version, so naturally I wonder what happens in ~two years when that version gets retired.
- timrogers 4y agoAuthor here! We think that, most likely, we will end up defaulting to the oldest version. We’ll share specific plans on that when we announce our first version deprecation. Just so you know, we don’t intend to deprecate `2022-11-28` in two years-ish - we plan to keep versions around for much longer than that. But we offer a commitment of at least 2 years for peace of mind.
- LennyWhiteJr 4y agoWhat does it mean for a field to be required in new API version but optional in the old version?
- timrogers 4y agoAuthor here! Are you thinking fields in a request or fields in a response?
- rattray 4y agoHey Tim, nice to see you here! You might consider behavior more like Stripe's here (disclaimer, former member of the stripe API platform team). As you're likely aware, Stripe defaults to the latest version for each user, and then stores that as the user's default API Version until they upgrade it at the account level. This works pretty well, and overall I'd recommend it. It may be better to give each API Key its own default API version, since different applications may expect different versions, and API keys can be a simple way to differentiate applications. Some of Stripe's client libraries also enforce sending a specific API version header to ensure the types are correct; my guess is that in practice, this is how most requests have their version dictated now, making the account-level setting a little anachronistic. Everything gets trickiest when it comes to webhook bodies, since the way the payload is rendered may be different across versions, so you can have one app create an object on version A and then a different app consume the webhook under version B and see the created object with a different shape. I'm not familiar enough with GitHub's API to know how best to handle this sort of thing. Anyway, good luck and happy to chat more.
- travisd 4y agoSince the author is responding to comments here: are there any changes coming soon that necessitated this?
- timrogers 4y agoAuthor here - you summoned me :) We have some small changes queued up, but nothing huge or earth-shattering. Our focus right now is on improving developer experience and consistency where we have some weirdness in our current API design that trips integrators up. Without versioning, we couldn't address those papercuts. We plan to release the first breaking version in the next few months.
- mpetrovich 4y agoMaking the version optional is a bad idea, IMO. It lets consumers use your API without versioning, which is like telling them, “here, create a time bomb that may or may not explode when the next breaking api change is released.” There’s zero practical user benefit to NOT specifying the version, so why not enforce it? You’re creating a footgun otherwise. Furthermore as others have pointed out, this is a purely cosmetic change. Using /api/$UNIQUE_STR in the URL vs. X-GitHub-Version: $UNIQUE_STR in the header are functionally equivalent, so… Why bother making this change then? What was suboptimal about the previous way? What benefit does this bring? EDIT: Serves me right for not reading the docs more carefully. From the docs [1]: Requests without the X-GitHub-Api-Version header will default to use the 2022-11-28 version. See phphphphp’s reply below for context. [1] https://docs.github.com/en/rest/overview/api-versions?apiVersion=2022-11-28#specifying-an-api-version https://docs.github.com/en/rest/overview/api-versions?apiVer...
- prepend 4y agoBecause they use calendar versioning the user benefit to not specifying is not having to keep track of a million different dates. I work with a lot of APIs that just have “/v1” or “/v2” as part of the endpoint so it’s easy to specify. Setting a header parameter to a specific date is a PITA and I certainly don’t want to look up the curl syntax whenever I do simple work. I think if they made it required, it would annoy people. So they didn’t.
- mpetrovich 4y agoI agree with you, so then why not stick with the previous /api/v2 url approach? And it would annoy me far more if my app that talks to GitHub inexplicably breaks in a few years because of a release I wasn’t aware of. These changes make no sense to me.
- knome 4y agoIt enforces the idea that the API is versioned per endpoint and not overall. You can update each endpoint in non-backwards compatible ways without having to update all of them. If you have it in the URL, it's likely libraries and custom scripts will just set the value in configuration instead of per-callsite. You don't want to have to wait to fix up some API or make non-updates on all the rest just to release a new version. edit: I agree that making it optional is a bad move
- 64bittechie 4y agoCould you elaborate why did you pick using a header instead of making the version number part of the URL? If the version is part of the URL, you have benefits such as - 1. It's easy to inspect the URL. For headers it's more involved. 2. Middleware (Proxies) can drop headers that they don't recognize. 3. Logging frameworks typically log URLs but don't log headers OOTB. As someone who has built a lot of APIs for a long time, I think the decision to use headers to communicate versioning information is not optimal.
- prepend 4y agoSounds like GitHub just committed to only supporting their api for two years. That sucks. I don’t think companies have to support forever but I don’t like the idea of having to rework my integrations every two years. Also specifying a date is very clunky. I’d rather they use semver (like a non-barbarian) and stick with breaking changes going into a major release.
- aliqot 4y agoshow them who's boss and ask for your money back.
- mberning 4y agoThis is the goofiest API versioning scheme I have ever heard of. Reminds me of opening a java project and finding stuff like joda-time-2004-11.jar.
- madeofpalk 4y agowhat's the difference between one string (a date) and other string (something vaguely resembling a number)?
- deleted 4y ago[deleted]
- prepend 4y agoSemver contains info by looking at the values. 2.0 introduces breaking changes over 1.7.1.3. What does 2022-11-28 vs 2022-11-30 mean? Or how many releases are between 2022-11-28 and 2042-11-28? I’m sure there’s a docs page spelling it out with details, but being able to compare two versions and tell if your code will work is pretty handy.
- micimize 4y agoMuch more important than moving the version request to the header is that it should hopefully clear up the confusion caused by REST being "v3" and GraphQL being "v4." As someone who has written some fairly intensive github integrations, I think the biggest thing github could do DX wise is unify the systems behind the two APIs and make them actually have parity. I'd always need both because they are a Venn Diagram, feature-wise. Though to be fair, I'm guessing it is a very difficult problem that every engineer on both teams dwells on regularly.
- onionisafruit 4y agoMaking a public graphql api was a huge misstep.They barely had an internal graphql api when they released the public api.
- larusso 4y agoI agree. I had the feeling when it was released years ago that the whole v4 API was kinda generated from a given database Schema. It was very usefull if you wanted to fetch data in a similar way than how the website does it. e.g. pull requests are part of repositories. I for instance wanted to query all pull requests for a given org and filter based on repositories. The search api was in most cases the only solution or go and mix and match with the v3 API.
- rogerz46 4y agoI agree. Graphql API is basically a database schema. That thing is lifting GH from heavy burden and will mislead their consumers like us.
- niels_bom 4y agoI remember something from the Changelog podcast that Github has a number of single- or two-person projects that are experiments but are then used by a non-insignificant amount of people. So then they choose to keep it on life support with minimal resource expenditure.
- borissk 4y agoIs this the way Microsoft and LinkedIn are going to version their public Web APIs in the future? I know Microsoft has a team that helps different groups unify the way they develop services, but wonder if that teams works with GitHub as well.
- timrogers 4y agoAuthor here. This versioning scheme was just developed within GitHub - so you shouldn't make any assumptions what this means for Microsoft's and LinkedIn's APIs.
- Existenceblinks 4y agoI know this is not the point but this REST API is way better than their "UpdateEnterpriseAllowPrivateRepositoryForkingSettingInput" GraphQL type, dang! I know it's not that REST .. it is what it is, probably annoyingly strict req/res, but it's very solid API. I'm glad they are trying to improve .. it.
- Existenceblinks 4y agoI'm not sure why don't we send diff(url) along with version in the header (if you have ever watched this https://www.youtube.com/watch?v=oyLBGkS5ICk https://www.youtube.com/watch?v=oyLBGkS5ICk Rich Hickey's talk) Diff format example: {added: [{"path-to-key": {..}}], removed: [], changed: [{"a/b/c": {prev: {type: "string"}, current: {type: "number"}}], moved: [{old: stuff1, new: stuff2}]}
- karmakaze 4y agoBackporting non-breaking changes for new features should only go back a certain number of versions of date peroid. This gives some motivation to be up to date and when clients decide they must update to use a breaking change don't have as many breaking changes to adapt to.
- indymike 4y agoHmm. So what happens when two versions are released in one day?
- layer8 4y agoThey can hop timezones. There’s (almost) always two dates that are “today” depending on timezone.
- macintux 4y agoThis is only for breaking changes, apparently, so presumably that situation won’t arise.
- timrogers 4y agoAuthor here. That's exactly our thinking - we are making the assumption that we won't want to release two versions with breaking changes on the same day. Who knows, maybe we will be proved wrong, but we think it's a safe bet.
- macintux 4y agoThanks. I would be remiss if I didn’t take this opportunity to ask: the current API for retrieving commit metadata relies on git’s information about the committer, but you have much better information available to you. You know who actually pushed the commit. In an enterprise setting, that’s a big deal, because it’s easy for users to have misconfigurations. We have no shortage of commits in our repositories from ec2-user or root. I don’t think it makes sense to replace the information git supplies, but could you please augment it?
- stonelazy 4y agoNaming the versions literally as date itself was well thought out.
- simonw 4y agoI kind of wish this wasn't only in a header. I frequently perform basic API exploration in my web browser - hitting https://api.github.com/repos/simonw/datasette/commits https://api.github.com/repos/simonw/datasette/commits for example - and there isn't a convenient way to add headers to those requests. I quite often do this kind of exploration on my iPhone in Mobile Safari (no need to get my laptop out just to quickly check what shape an API is), which is even less convenient for sending custom headers.
- brandur 4y agoI wonder if they might be amenable on that one. (If any GitHub staff is reading this.) The proposed scheme is fairly similar to Stripe's, and although Stripe mainly uses the `Stripe-Version` header for versioning, its API has also always allowed you to alternatively send a `?_stripe_version=<version>` query parameter which it'll respect. Stripe's API implementation definitely had its share of legacy cruft that added up and made things more difficult to maintain, but out of all of it, I don't remember having to support that alternative `_stripe_version` parameter ever really being a maintenance headache. The leading underscore made sure that even as the API expanded, it never accidentally collided with parameters on any other endpoint.
- onionisafruit 4y agoOld github would have been amenable. Current github has to convince a product manager who barely knows what an api is.
- prepend 4y agoThis definitely seems like a “current GitHub” decision where some project manager chain signed off after being “trained” on the benefits. It has a very Microsoft feel of a technically correct if everything goes right (eg, windows registry) but overly complicated and not something that would survive an open source dev review. That being said, it’s not the end of the world. It’s just eventually these straws will add up to something really bad.
- 4y ago
- okhudeira 4y agoAll the discussions around header vs. path versioning reminds me of this post by Troy Hunt of Have I been Pwned. > In the end, I decided the fairest, most balanced way was to piss everyone off equally. Of course I’m talking about API versioning and not since the great “tabs versus spaces” debate have I seen so many strong beliefs in entirely different camps. https://www.troyhunt.com/your-api-versioning-is-wrong-which-is/ https://www.troyhunt.com/your-api-versioning-is-wrong-which-...
- bilalq 4y agoThis is similar to the versioning scheme used by AWS and it worked well there. Versioning was rarely done, but this was a clean scheme for surfacing breaking changes to users. https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/locking-api-versions.html https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-... It is a little surprising that the version defaults to the 2022-11-28 rather than defaulting to latest if omitted, but I guess that's a way to err on the side of not breaking old users when they upgrade an SDK.
- timrogers 4y agoAuthor here. You've hit the nail on the head on why we default to 2022-11-28 - it's all about protecting the hundreds of thousands of of existing GitHub integrations that rely on our current behavior.
- mdaniel 4y agoA friendly reminder that if you're going to use in these "date-ish" headers in a yaml context, ensure that you quote the value because `x-github-api-version: 2022-11-28` deserializes as `{"x-github-api-version":"2022-11-28T00:00:00"}`
- macintux 4y agoArgh. Man, that’s a pet peeve of mine in general: it feels like most languages really want a date value to be a datetime. I’ve had to write libraries for Erlang and Python to support concepts like “August” without interpreting them as “August 1st 00:00:00”.
- dgudkov 4y ago>When we do decide to end support for an old version, we’ll announce that on our blog and via email. Blogs/email shouldn't be the only channel. Announce the retirement date with an HTTP header right in the response. In this way, developers can create automated alerts about soon depreciation. In other words, depreciation announcements should be machine-friendly, not just user-friendly.
- amhenk 4y agoThis is a neat idea. Are there examples of this in the wild?
- timrogers 4y agoAuthor here. We actually use deprecation headers in our GraphQL API.
- xavdid 4y agoI like the idea of this, but in practice, I'm not looking at responses for an API unless I'm actively developing on it. If I'm doing a maintain-occasionally project, then I'll never see the deprecation response. I'm also unlikely to set up an automated alert for a random API I used one time (tricky to do without external tooling, like Zapier). I'm much more likely to plug an email into a form, since that's all set up for me already. That said, as long as there's multiple ways to get notified, more is probably better.
- timrogers 4y agoAuthor here. I think it's a pretty nice idea to include deprecation information in the response headers as another way to keep API integrators informed - alongside written forms of communication like blog posts, changelog entries and emails. We'll discuss that internally. As @xavdid noted, the reality is that most people won't see these headers, but it's a nice power user feature.
- plmpsu 4y agoAny reason for going with a header instead of media types? I found media types convenient in that they can be explicitly specified in an OpenAPI specification.
- timrogers 4y agoAuthor here! Honestly, we found that media types within the GitHub API had just got pretty confusing as we use them for so many things - "feature previews", response formats, versions (https://docs.github.com/en/rest/overview/media-types?apiVersion=2022-11-28 https://docs.github.com/en/rest/overview/media-types?apiVers...). We didn't want to overload them anymore. Just so you know, we published OpenAPI specifications for all of our API versions on GitHub: https://github.com/github/rest-api-description/tree/main/descriptions/api.github.com https://github.com/github/rest-api-description/tree/main/des...
- yewenjie 4y agoIs this model suitable for smaller projects? What does the development side look like for maintaining so many parallel versions?
- timrogers 4y agoAuthor here! Supporting many API versions in parallel definitely has an overhead from an engineering perspective - but, as the blog post says, we thought it was crucial that we unlock the ability for us to evolve our API whilst still providing consistency to existing integrators. Some form of versioning was the only way we could see to do that. We've built some pretty neat tooling and abstractions internally to make it easy for teams across GitHub to build and test multiple API versions. We hope to publish a blog post about that in the near future.
- jerrygoyal 4y agoNotion follows the same version approach. They initially made version header optional but now they made it required for api calls. Maybe GitHub team should learn from their experience. https://developers.notion.com/reference/versioning https://developers.notion.com/reference/versioning
- nesarkvechnep 4y agoVersion in the URL and REST are oxymorons.
- nik736 4y agoCan someone explain to me please how this is handled within the internal codebase. I assume that it's not a lot of if statements or copying whole API directories with every release but something much simpler? Thanks! :)
- lnenad 4y agoThere's multiple of ways of doing this but let's assume some sort of routing model is used so you can have global rules based on the version provided that redirects/executes (depending on the layer where these rules are enforced) the proper code. From a code standpoint it can mean having a separate route group in your code for an API version, or it means that you have multiple routes for the "same" functionality per specified version, or it can mean something else entirely depending on how your code is structured. They most definitely aren't copy pasting parts of their project to support this.
- timrogers 4y agoAuthor here. We plan to publish a blog post in the next few months that explains how we do this under the hood. We have some pretty nice abstractions and tooling to make it as maintainable as possible.