I'm currently in charge of a pretty classic, GET things out, and POST things in API. If my API supports that some non-IT office guy can get his daily report through the browser, and the API at the same time has the power and flexibility needed for someone with IT skills to do more then I've won. Both me and my users gain by me taking extra steps to make it as accessible as possible.
I also fail to see how versioning through urls break anything, except if the newer client no longer has support for v1. In both versioning schemes you specify which version of a resource you're sending/wants to receive, in one scheme you do it through a header, in the other through the url.
>> If a client using v1 communicates with a client using v2, then they will see two separate sets of resources and they would never have the same identifiers for (what should be) the same resources.
Maybe we're defining versioning differently. I strive to make resource types backwards compatible, but if I can't then it's either a new version or a creating a new more specialized resource type for the specific problem.
Most APIs I work with wouldn't work this way even for read-only access because of authentication requirements. I guess you're using something like HTTP digest auth with usernames and passwords?
Even so, that still works for your use case as long as your users are happy with a default version. e.g. requests without a specific version get the latest version, or requests without a specific version get version 1, or requests without a specific version get the latest stable version that changes from time to time. I don't think I've ever come across non-IT office guys that have more complex versioning requirements than that.
> I also fail to see how versioning through urls break anything, except if the newer client no longer has support for v1.
Here's an example:
Client A (using version 2), talking to Client B (using version 1):
> Here is a friend suggestion for person https://example.com/v2/people/foo
Client B:
> Okay, I'll add them to my contacts. My contact list is now:
https://example.com/v1/people/foo
https://example.com/v2/people/foo (error: cannot parse)
Had the URIs truly been identifiers, this would have looked like:Client A (using version 2), talking to Client B (using version 1):
> Here is a friend suggestion for person https://example.com/people/foo
Client B:
> Hey, I already know that guy!
Once you break the identity part of URIs, you start getting a tonne of these awkward problems to work around. URIs are meant to be the primary keys of the web, and you're going against the grain of the medium when you break that.
To put it another way, imagine if websites had to change every page URI from /html4/ to /html5/ when they switched versions. That's a whole lot of work and breaking things for no reason. I'd rather follow how the web was designed to work and not create so much extra work.
As for auth a simple token as Github does is enough, and github lets you use it as a header or a get param.
Your choice of HTML 4/HTML 5 for comparison seems aptly poor. Instead of clear versioning, old browsers get HTML they don't understand and fail unexpected, unpredictable and ungratefully ways. The exact opposite of what we should want for API.
No, I mean API clients.
> I can't come up with any reason why two client applications would be sharing full API URLs directly with each other, that seems like very poor design.
URIs are the primary key for resources on the web. If two clients want to talk about the same resources, then they need to agree on an identifier, and that's exactly what URIs are designed for.
> As for auth a simple token as Github does is enough
The design criteria in this example is "Can be typed into a browser address bar by a non-technical person". I don't think auth tokens meet that criteria.
> Your choice of HTML 4/HTML 5 for comparison seems aptly poor. Instead of clear versioning, old browsers get HTML they don't understand and fail unexpected, unpredictable and ungratefully ways.
You're conflating two different things there; how versions are communicated, and the compatibility strategy. Whether or not HTML did a good job of maintaining compatibility between different versions, do you agree that changing the URI of every web page on the web to communicate when they change HTML versions is a bad approach?
Basic auth (over https only) actually, I'm even advocating it. We support expirable tokens as well.
>> requests without a specific version get the latest version, or requests without a specific version get version 1, or requests without a specific version get the latest stable version that changes from time to time
The only way for me to go would be option 2: requests without a specific version get version 1. Any other choice and I'd have customers API integrations breaking, because many of them would not have specified their version mimetypes correctly and would therefore get the default version, which would at some point diverge from their expectations.
>> URIs are meant to be the primary keys of the web, and you're going against the grain of the medium when you break that.
In that context your example makes sense, I just don't see that as realistic problem. In real life URI aren't as static as we pretend. How many companies would make sure the resource urls are still valid after changing the company and domain name?
The real identifier in your case is "foo" and "people" is the type. Accepting that sets you free to do versioning as you please and to save 90% characters in all ids :)
In the end we should design apis for our users, not for our selves. My clients are always non-IT departments, often in enterprisy environments, and if they can get 2-4 hours allocated from IT in the next 6 months to do some API integration, they are lucky. So I design my api for maximum simplicity, and maximum longevity of the using scripts, because if I wanted to make a breaking change, I'd have to wait 6 months before all customers could be expected to have transitioned.
Most of my api users couldn't tell you what a mimetype is btw., but a v2 in the url would make complete sense.
I get where you're coming from, on our latest api version I started out wanting to do full HATEOAS (Bought and read this great book http://www.designinghypermediaapis.com/), but in the end I had too much trouble getting my test customers migrated, so I had to scale back on the desgin goals. Scaling back to what worked for everybody was very informative and the api is now, imo, the better for it.
If I need to bump the vesion it'll be with a vx in the url. An id is a simple non-globally unique thing, that you use to build a url etc.
"Some other people might write code that does things incorrectly and then their software might break" is something you can say about any API style, it's nothing special to media type versioning. If many of your customers are writing code that integrates with your API incorrectly, you don't have an API design problem, you have a poor communication problem, and that's going to hurt you in all kinds of ways.
> In real life URI aren't as static as we pretend.
They are static if you don't deliberately break them; I'm just pointing out some of the consequences if you choose to.
> How many companies would make sure the resource urls are still valid after changing the company and domain name?
Companies are laser focused on this if they rebrand. Companies love their search rankings. But how common is it to rebrand? Optimise for the common case, not the uncommon ones.
> The real identifier in your case is "foo" and "people" is the type.
You're turning URIs from an opaque identifier clients can use as-is to a compound structure that clients have to parse, manipulate, and (re)generate. You're putting more logic on the client, and thus giving client developers more rope to hang themselves with immediately after saying they can't be trusted to get things right.
This is not designing for maximum simplicity. Designing for maximum simplicity is to have an API that says "here's a link; follow it", not an API that says "here's an ID, generate a URI from it according to these rules we set out in our documentation, that are different for every type of resource". The latter is more work and more error prone.
>> "Some other people might write code that does things incorrectly and then their software might break
Welcome to my world :)
>> is something you can say about any API style, it's nothing special to media type versioning
True, but mimetype versioning still makes things more complicated for my average user.
>> If many of your customers are writing code that integrates with your API incorrectly, you don't have an API design problem, you have a poor communication problem, and that's going to hurt you in all kinds of ways.
Sorry, but no. We have full Swagger interface, examples for all major operations in 4 different languages, many pages of documentation and tutorials, and very clear and informative error messages for most situations. Still people will write and say it doesn't work, without having read any docs or even looked at the response.
>> This is not designing for maximum simplicity. Designing for maximum simplicity is to have an API that says "here's a link; follow it", not an API that says "here's an ID, generate a URI from it according to these rules we set out in our documentation, that are different for every type of resource". The latter is more work and more error prone.
I'll reiterate, we're probably designing for different clientele. I'd wager my old Amstrad that most of my users would strip any url'y parts of ids I'd return and just store, what they'd perceive to be, the "true" id in their database, because they only have 20 cloumns allocated in their weird mainframe system, named info1-10 and extra1-10, and the latter only allows 32 chars.
But also consider this: A user uploads a resource through the perfect HATEOAS api, he get's back a big object with a unique url id, and links to all the actions he can perform. It doesn't really makes sense for him to store anything other than the URI though, because I might add more actions later, so he'd have to requery the URI to get links to the latest actions anyway. So for any operation he wants to perform, he should GET URI, parse and follow link with appropriate parameters. Also, in that scenario my system gets hit twice for any operation. Compare that to: Replace parameters into https://example.com/people/{id}/poke and fire request. I'd argue that the latter is conceptually simple.
Very soon we'll start on a new api for our ui, and on that there will be no compromise :)
That also rules out using any HTTP method other than GET. The browser address bar doesn't seem relevant here, and if it were, then it would rule out the vast majority of APIs.
Versioning through the URL breaks interoperability of clients using different protocol versions. If a client using v1 communicates with a client using v2, then they will see two separate sets of resources and they would never have the same identifiers for (what should be) the same resources.