Actually, we haven't broken (on purpose) the API in a long time. Let's make sure we're clear on what "breaking" changes are NOT.
They are NOT: - Adding new endpoints to the API - Adding new attributes to the response of an existing endpoint ^^ In my experience, this tends to be the bulk of our API changes which just warrants a minor upgrade... And I hope we're not changing the datatype of a minor field 13 times :) On Thu, Oct 19, 2017 at 3:50 PM, Chris Lemmons <alfic...@gmail.com> wrote: > I thought about that. But I'd like to reserve the major version of TC > for actually major things. Making the API control the TC version > number feels like the tail wagging the dog. Most other projects don't > do it that way, either. > > It might not be so bad, except that we make breaking changes on a > fairly regular basis. It would feel weird revving TC to version 14 > simply because we changed the datatype of a minor field for the 13th > time. > > And likewise, sometimes we don't change the API. At the moment, we're > pretty API-focused. But focuses change and we might have whole > releases focused on UI or integrations. It would be strange to rev the > API when it didn't change. The point of Semantic Versioning is to > communicate changes to the API in a way that is consistent, easy to > apply, and grokkable by humans and computers alike. > > I think I'm still -1 on locking the API version to the TC version. > > On Thu, Oct 19, 2017 at 3:39 PM, Robert Butts <robert.o.bu...@gmail.com> > wrote: > > @alficles What if we do both Semantic Versioning, and tying the API > version > > to the TC version? So, we would have to increase the TC major version > with > > any breaking API changes (which may inconveniently be minor to the rest > of > > TC). > > > > But, that has the big advantage of letting us programmatically tie the TC > > version to every client. So, with a small upfront cost writing the code > to > > read the `/VERSION` file into the client binaries when the RPM is > > built--for example, in Go with ```-ldflags "-X lib.Version=`cat > > ../VERSION`"``, and then concatenating that string into the endpoint > > request---we could synchronise all our versions, and essentially not have > > to think about versions, not have to manually update clients, not have to > > worry about what endpoint was added in what version. > > > > That alleviates a huge percentage of the brain and keyboard work we > > currently have to do surrounding versioning. > > > >> Our API version should have 3 numbers, though: major, minor, patch > > > > -1 on putting the patch in the URI, it's verbose and unnecessary, bug > fixes > > don't make things incompatible and are unlikely to cause confusion. > > +1 on putting the patch in a header, e.g. `X-API-Version: 1.3.deadbeef`. > > Header makes it easy to debug, in the rare event it's necessary, without > > cluttering the URI or Body. > > > > > > On Thu, Oct 19, 2017 at 3:14 PM, Chris Lemmons <alfic...@gmail.com> > wrote: > > > >> Heh, I agree on the arguing about API versions, but I just want to > >> hand the task to Semantic Versioning, so we can just ask some simple > >> questions like "did we break backward compatibility" and "did we add > >> something" and figure out what number to put on the route. And we > >> avoid arguments entirely. (We have to get used to the idea of revving > >> the top version, though, because we break compatibility a lot.) > >> > >> On Thu, Oct 19, 2017 at 3:01 PM, Jeremy Mitchell <mitchell...@gmail.com > > > >> wrote: > >> > In reality, we really did break the API when we went from mysql (TC > 1.8) > >> to > >> > postgres (TC 2.0) and strings became ints, for example, so the api > should > >> > really be 2.x anyhow imo. > >> > > >> > Anyhow, the real reason i like syncing the api version to the TC > version > >> is > >> > for simplicity and we don't have to argue all day about api versions. > :) > >> > > >> > > >> > > >> > > >> > > >> > On Thu, Oct 19, 2017 at 2:54 PM, Chris Lemmons <alfic...@gmail.com> > >> wrote: > >> > > >> >> Interesting idea. I think, though, it's better to keep API versions > >> >> separate from TC versions. Many versions of TC won't rev the API at > >> >> all. I'd prefer to go all in on Semantic Versioning. > >> >> > >> >> I think it could work like this. For a given route, use the route > >> >> defined for the most recent version not later than the requested > >> >> version. So, if the quux endpoint is introduced at 1.2, and changed > at > >> >> 1.4, these requests would be served by these routes: > >> >> > >> >> GET /api/1.1/quux → 404 > >> >> GET /api/1.2/quux → Served by 1.2. > >> >> GET /api/1.3/quux → Served by 1.2. > >> >> GET /api/1.4/quux → Served by 1.4. > >> >> GET /api/1.5/quux → Served by 1.4. > >> >> > >> >> The advantage of this is that it's relatively easy to implement in > the > >> >> router, though there are admittedly some challenges on the Perl side > >> >> of things. If we want to be clever, we can allow a client to elide > >> >> later values and just assume they meant the latest. But we don't need > >> >> to start out clever. > >> >> > >> >> Our API version should have 3 numbers, though: major, minor, patch. > We > >> >> should expose these versions in a new /version endpoint that will > >> >> allow clients to self-configure and detect new versions. > >> >> > >> >> As an alternative to strict semantic versioning, we could consider > the > >> >> first two numbers to be the "major" number for Semantic Versioning > >> >> purposes. I think this hurts discoverability in the community, but it > >> >> matches our current practice, for the most part. I think this would > be > >> >> a reasonable compromise, if people aren't comfortable increasing the > >> >> first number every time we break compatibility in a revision. > >> >> > >> >> Lastly, we should recognize that we may need to retire API versions. > >> >> Eventually, we may make changes to the DB that mean the information > >> >> provided in a prior version simply does not exist. To that end, we > >> >> should provide a /minversion (or similar) endpoint that returns the > >> >> lowest API version supported by that server. Queries below that value > >> >> cannot be guaranteed to succeed. (Or would it be better to cut it off > >> >> an say that no queries for previous versions are permitted?) > >> >> > >> >> I'm +1 on Semantic Versioning. I'm a lukewarm +1 on a variant that > >> >> uses the first two numbers as "major" and the last as "minor". I'm -1 > >> >> on locking it to the version of TC. I'm +1 on providing /version and > >> >> /minversion endpoints to allow clients to auto-detect > incompatibility. > >> >> > >> >> On Thu, Oct 19, 2017 at 12:54 PM, Jeremy Mitchell < > >> mitchell...@gmail.com> > >> >> wrote: > >> >> > With the Golang API rewrite, we were not planning to break any APIs > >> but > >> >> > rather simply port them to Golang thus we did not see the need to > rev > >> the > >> >> > API version from 1.2. However, maybe this is good opportunity to > get > >> our > >> >> > API version inline with the TC version. > >> >> > > >> >> > So, my thought is that our Golang API's look like this: > >> >> > > >> >> > GET /api/v2.2/foos <-- this would return foos served by golang > because > >> >> > we've ported this endpoint > >> >> > GET /api/v2.2/bars <-- this would return a 404 served by golang > >> because > >> >> > we've have NOT yet ported this endpoint > >> >> > > >> >> > and our perl apis are still acessible in 1.2 > >> >> > > >> >> > GET /api/1.2/foos <-- this would return foos served by perl > >> >> > GET /api/1.2/bars <-- this would return bars served by perl > >> >> > > >> >> > This has 3 benefits: > >> >> > > >> >> > 1. by revving the version, it signals the community that something > has > >> >> > actually changed in our API and in this case, the change may > simply be > >> >> the > >> >> > fact that we now have nifty golang implemented APIs that you might > >> want > >> >> to > >> >> > explore. > >> >> > 2. it provides the ability to stay on the perl apis by specifying > 1.2 > >> if > >> >> > that is what you want to do. maybe you are not much of a risk > taker... > >> >> > 3. it does actually provide license to break the new golang apis if > >> >> needed > >> >> > (to make them better) because the major version has incremented. > it's > >> >> nice > >> >> > to have that option if needed. > >> >> > > >> >> > Also, going forward, I propose the TO API version follows in > lockstep > >> >> with > >> >> > the TC version...which means the minor version will keep > >> >> incrementing...GET > >> >> > /api/v2.2/foos...GET /api/v2.3/foos..which means functionality can > be > >> >> added > >> >> > to the API "in a backwards-compatible manner" > >> >> > > >> >> > Remember, at some point TO will only be the TO API so why wouldn't > >> this > >> >> > component follow the versioning that the other components do? Just > my > >> >> > thoughts. > >> >> > > >> >> > Jeremy > >> >> > > >> >> > On Tue, Oct 17, 2017 at 12:02 PM, Robert Butts < > >> robert.o.bu...@gmail.com > >> >> > > >> >> > wrote: > >> >> > > >> >> >> I'm fully +1 on Semantic Versioning. We discussed it briefly on > the > >> >> list a > >> >> >> long time ago, but we haven't really been doing it. > >> >> >> > >> >> >> That said, versioning requires a lot of code/work that simply > doesn't > >> >> exist > >> >> >> today. That's the reason we haven't been doing it properly. > >> >> >> > >> >> >> The Go Traffic Ops has Semantic Versioning built-in to the > Routing, > >> but > >> >> >> Perl support is close to nil. Perl currently has an easy way to > say > >> >> >> "include all the routes in this version number", But there's no > way > >> to > >> >> say > >> >> >> "this route is 1.2 only, and this route is 1.3 only" -- we'd have > to > >> >> >> duplicate TrafficOpsRoutes.pm, with only a few lines changed, and > >> >> likewise > >> >> >> duplicate changed functions. It needs a framework. Or we could > just > >> wait > >> >> >> until Perl goes away. > >> >> >> > >> >> >> That said, Go, especially the client, doesn't completely support > >> Minor > >> >> >> Versions like it should, either. Consider adding a new field to > >> Delivery > >> >> >> Services. Per Semantic Versioning, that field MUST not be > returned by > >> >> the > >> >> >> old version `GET`, and MUST not be set if passed by a `POST`. The > Go > >> >> server > >> >> >> supports that in the Routing, via different endpoints, but > there's no > >> >> >> Struct framework or pattern. And the client completely doesn't > >> support > >> >> it. > >> >> >> In Go, we probably need a set of anonymously-nested structs, `type > >> >> >> DeliveryServices12 struct { Foo int }; type DeliveryServices13 > struct > >> >> >> {DeliveryServices12; Bar string}`. But that simply doesn't exist > >> today, > >> >> and > >> >> >> will take development time to write. > >> >> >> > >> >> >> Option 2: Absolute Versioning. Instead of Semantic Versioning, we > >> could > >> >> >> have a single version, and break compatibility with each new > version. > >> >> So, > >> >> >> all new features (breaking or not) would go in a new version, and > all > >> >> >> clients must check the version, and refuse to operate on a > different > >> >> >> version. So you'd be required to have a client version matching > the > >> >> server > >> >> >> version; users are not allowed to talk to new servers with old > >> clients. > >> >> >> > >> >> >> Option 3: No Versioning. We get rid of the version number. > Endpoints > >> >> are at > >> >> >> `/api/foo`. Over the last few years, we have _repeatedly_ broken > the > >> API > >> >> >> for the same version. A 1.2 client from three years ago will fail > >> >> >> catastrophically if connected to a Traffic Ops serving `/api/1.2` > >> >> today. In > >> >> >> practice, as we've been developing, we have no version, the > version > >> >> number > >> >> >> is meaningless and confusing. If we're going to continue breaking > >> >> >> compatibility without updating the version number, we should get > rid > >> of > >> >> it. > >> >> >> Then at least the version itself won't be confusing and painful. > >> >> >> > >> >> >> What's the consensus here? Does everyone agree with Semantic > >> >> Versioning? Do > >> >> >> we want to commit to requiring it? Is there a consensus? Or > should we > >> >> take > >> >> >> a vote, whether to require Semantic Versioning, Absolute > Versioning, > >> or > >> >> No > >> >> >> Version? > >> >> >> > >> >> >> > >> >> >> On Thu, Oct 12, 2017 at 7:39 AM, Dave Neuman <neu...@apache.org> > >> wrote: > >> >> >> > >> >> >> > Traffic ops currently does not handle versioning very well. I > >> think > >> >> we > >> >> >> do > >> >> >> > support 1.1 and 1.2 versions of the API, but I think there are > >> only a > >> >> few > >> >> >> > (maybe asns and deliveryservices) that are actually different. > >> >> >> > Versioning is something we look to improve as we move to the > golang > >> >> >> version > >> >> >> > of the API. > >> >> >> > > >> >> >> > On Thu, Oct 12, 2017 at 6:50 AM, Eric Friedrich (efriedri) < > >> >> >> > efrie...@cisco.com> wrote: > >> >> >> > > >> >> >> > > Does Traffic Ops expose a semantic version number as part of > its > >> >> API? > >> >> >> > > > >> >> >> > > http://semver.org/ > >> >> >> > > "Given a version number MAJOR.MINOR.PATCH, increment the: > >> >> >> > > > >> >> >> > > 1. MAJOR version when you make incompatible API changes, > >> >> >> > > 2. MINOR version when you add functionality in a > >> >> >> backwards-compatible > >> >> >> > > manner, and > >> >> >> > > 3. PATCH version when you make backwards-compatible bug > fixes. > >> >> >> > > > >> >> >> > > “ > >> >> >> > > > >> >> >> > > We have some TO clients and would like to improve their > backwards > >> >> >> > > compatibility. Without this version number, it is not easy to > >> >> determine > >> >> >> > > which fields in the API are supported by any given version. > >> >> >> > > > >> >> >> > > Thanks, > >> >> >> > > Eric > >> >> >> > > > >> >> >> > > > >> >> >> > > >> >> >> > >> >> > >> >