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.
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.
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
Here specifically I was suggesting that the /v2/ in the URL would make people using the API more likely to set the /v2/ in their app to use it across all calls rather than different per endpoint versions.
It looks like the calls are in the version rather than the version being in the calls.
It's a general problem I see with any REST API that tries to version that way. Version isn't a strict hierarchical "owns" relationship and embedding it early in the URL sort of violates REST principles in what the folder path of a URL is meant to imply. (Admittedly, that's a bit of a more strict interpretation than most people pragmatically follow when building REST APIs, but it is an interesting and useful strict interpretation so worth bringing up and examining.)
If you are versioning individual endpoints it might make sense to use URLs like: some/endpoint/v1 and some/endpoint/v2
That makes it more clear that "some/endpoint" "owns" that relationship and kind of/sort of what "exactly" is being versioned. If you must put a version number in the URL.
That said, REST has always been about content negotiation as a long held tenet, and that has always been about using the right Headers (since the earliest HTTP 1.x apps), and I've always felt like complaints that you can't send the right version Header reflects primarily on bad tools that don't understand HTTP (and REST) as well as they should. Sending Headers is an important part of HTTP. I don't think it should be harder to send the right Headers than to embed things that would be Headers into the URL. Though that's just my somewhat strong opinion on the subject.
But now I think that the versions are not part of the resource path, just as starting the path with /api doesn't mean the API is part of the resource. The versions are part of the api path. If I had a URL that was /api-v1 and /api-v2 it would be more obvious, perhaps, that the URLs are addressing different API implementations, and everything that came after was the RESTful bit. Having /api/v1 and api/v2 as the prefixes isn't quite as clear on that point, for sure.
The reason I like having the version in the path is it makes it a bigger deal for the implementer when they're making breaking changes. Having a per-endpoint, slightly hidden way of versioning endpoints might mean it's harder for them to intuit quite how many changes are flying at their API's consumers.
I think you are almost assuming the implementer doesn't abstract the URL routing in some way and has to care about about every possible URL route? In practice there is often very little difference on the implementer side between routing `/api/v{id}/some/route` and pulling in the version number as a route parameter and picking up a version number from a header. The implementer is still just seeing a version number parameter injected either from their routing framework or their header dictionary. In both cases the amount of code they see is roughly the same. In many cases all "versions" of the code might only be a single "Controller". Outside of a few languages such as PHP there's few languages that have a direct 1:1 between URL paths and "Controllers" or "Source Files" or anything resembling that. At some point there's always some intuition that side-by-side versions imply side-by-side code and the "tech debt" sense of that maintenance version, but that intuition comes from numbers of classes and size of classes and indirect measurements like PR cycle time and Sprint planning estimates, and is never directly connected to URL routing versus Header negotiation. (Again, in modern languages with modern routing frameworks. Obviously if you have to drop a PHP or ColdFusion file for every API endpoint you'll feel URLs a lot more painfully than that.)
Really? Don't you do this all the time for everything beyond a simple GET? From my experience it's far preferable than URL versioning because you can version on an individual endpoint. Right now I'm consuming Versions 0.9, 1.0 and 2.0 from a vendor; it would be way nicer to set individual headers than somehow mananging multiple endpoints.
That being said, I don’t call multiple versions of an api so maybe it’s nice to just be able to call multiples.
I imagine that it’s pretty easy to manage with the url version as you’re still just storing one endpoint and appending the version depending on what you would like. So programmatically you just change a config variable with the version you want.
But it seems like the version on changes with breaks so if you’re calling different versions you have to handle the input and output differently anyway.
I don't understand the difference. What makes it nicer?
I did a quick search and couldn’t see any docs on this use case.
And it behaves the same way as `curl --header "" --header ""` in that it's additive:
$ curl -vK <(printf 'header = "alpha: 1"\nheader = "beta: 2"\n') httpbin.org/getThe benefit of this new versioning approach is that they can maintain backwards compatibility for existing implementations while introducing breaking changes for new implementations to benefit from.
In an ideal world, sure, they should have implemented this from the start, but they didn’t, so going forward they have to accommodate both existing implementations (by not breaking anything) and new implementations (by providing features that would break existing implementations).
They’re basically just implementing stripe’s well-understood and battle tested approach for versioning, while maintaining backwards compatibility. I am struggling to see any problems with the approach, in fact, it seems like the only right approach (?)
That certainly addresses the footgun I mentioned.
EDIT: From the docs: Requests without the X-GitHub-Api-Version header will default to use the 2022-11-28 version.
At some point the default 28th Nov 2022 version is unsupported... So what is served must change... Either it's the latest at the time or the behaviour of receiving a response without providing the header is removed.
I'll take the bait, like C++?
> comfortable making incompatible updates
Incompatible how? You specify the version, your semantics are of that version.
> When a new REST API version is released, we’re committed to supporting the previous version for at least two years (24 months).
The blog post suggests that we might find out some of the API changes that warranted this change as early as next month, but it would have been great for this blog post to include some examples of changes that were coming.
I don't think it's a strong point.
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?