You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@trafficcontrol.apache.org by "Eric Friedrich (efriedri)" <ef...@cisco.com> on 2017/10/12 12:50:15 UTC

Traffic Ops API Semantic Versioning

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


Re: Traffic Ops API Semantic Versioning

Posted by Jeremy Mitchell <mi...@gmail.com>.
Yes, when TC goes from 2.2 to 2.3 to 2.4, the TO API would follow those
versions. But since those are minor version upgrades, we can only "add
functionality [to the API] in a backwards-compatible manner" per your semantic
version definition above.

If we introduce API breaking changes, the API would go to 3.0, which would
pull up the version of TC to 3.0. (personally, i don't envision these types
of API changes for a while).



On Thu, Oct 19, 2017 at 2:12 PM, Eric Friedrich (efriedri) <
efriedri@cisco.com> wrote:

> If we want our TC version to match our API version, it looks like we would
> rev the version every TC minor release, even though it may not contain
> breaking changes?
>
>
>
> > On Oct 19, 2017, at 2:54 PM, Jeremy Mitchell <mi...@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.butts@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 <ne...@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) <
> >>> efriedri@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
> >>>>
> >>>>
> >>>
> >>
>
>

Re: Traffic Ops API Semantic Versioning

Posted by "Eric Friedrich (efriedri)" <ef...@cisco.com>.
If we want our TC version to match our API version, it looks like we would rev the version every TC minor release, even though it may not contain breaking changes? 



> On Oct 19, 2017, at 2:54 PM, Jeremy Mitchell <mi...@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 <ro...@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 <ne...@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) <
>>> efriedri@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
>>>> 
>>>> 
>>> 
>> 


Re: Traffic Ops API Semantic Versioning

Posted by Chris Lemmons <al...@gmail.com>.
> do bug fixes qualify as breaking changes?

Not necessarily. I gave an example of one that did and one that
didn't. It's not the "bugfixiness" of it that matters, but whether it
breaks compatibility.

> It just feels to me like the TO API is a first class citizen of TC

Aye. But it's a citizen with different needs than most of the other
citizens. The numbers communicate different things. In TC, the version
number serves to organize work into discrete deliverable components
and the major and minor version numbers communicate the scope of the
changes to be expected. In TOAPI, the version number (imo) should
serve as a signifier of compatibility. A client should be able to
present its version to a server and be assured that its messages will
either be understood or rejected entirely, not misunderstood or
partially applied. A client should be able to ask a server for it's
version and be sure that the server version is sufficient for the
features the client wishes to use.

The goals are similar, but not really the same. Trying to apply the
TOAPI version to TC generally feels a bit like the tail wagging the
dog. Fundamentally, a Semver TOAPI version is descriptive and our TC
Version is prescriptive. I don't know that the two goals are
sufficiently aligned to keep them in lockstep.

On Thu, Oct 19, 2017 at 8:17 PM, Jeremy Mitchell <mi...@gmail.com> wrote:
> chris,
>
> the signing_algorithm thing does sound like a breaking change and sounds
> like it could warrant the move from 1.2 to 2.x...
>
> do bug fixes qualify as breaking changes?...hmm...i really hate to think
> that simple bug fixes would require a major version upgrade but i see your
> point.
>
> It just feels to me like the TO API is a first class citizen of TC (or soon
> will be) and like other TC components, it's version should follow along.
>
> Just my 2 cents. I know others feel like this could simplify a lot of
> things across components but I'll let them speak for themselves.
>
> Jeremy
>
> On Thu, Oct 19, 2017 at 5:03 PM, Chris Lemmons <al...@gmail.com> wrote:
>
>> I think we can reasonably define "backwards-compatible change" to mean
>> "a client of the prior version can communicate with the future version
>> and all it's legitimate messages and sequences thereof are understood
>> to mean the same as they did in the prior version". We can reasonably
>> expect clients to ignore fields they do not understand in a response.
>>
>> Some examples:
>>
>> We add a new endpoint. This is backward compatible, because an old
>> client won't know to communicate with it.
>>
>> We add a field to an existing endpoint. For a read-only endpoint, this
>> is backward compatible. If the field is required on a post/put,
>> however, it would not be. Likewise, if the server assumes a "zero
>> value" instead of "not modified" on a post/put, that would also be not
>> backward compatible. If the field can be omitted, and the field isn't
>> modified on the server when it isn't present, it is backward
>> compatible.
>>
>> A more concrete example:
>>
>> In the URI Signing PR, we change the underlying database value from
>> "signed, boolean" to "signing_algorithm, varchar". Previously, the
>> "signed" boolean meant "using url_sig". Now that we're trying to add
>> "uri_signing" as an option, boolean doesn't make sense. But to
>> mitigate the change, we're leaving the existing API field "signed" as
>> a boolean that means "using url_sig".
>>
>> This is still not quite backward compatible, though. A client that
>> knows nothing of the new "signingAlgorithm" field can read a DS that
>> has "signed == false" and update it to "signed == true", then try to
>> undo it's change by reverting to what it used to be "signed == false".
>> For the old server version, this was a correct "undo" step. For the
>> new server version, this step can potentially change a DS from
>> "signingAlgorithm == uri_signing" to "signingAlgorithm == none". Since
>> the meaning of this sequence of messages is different, the change is
>> not backward compatible.
>>
>> A "bugfix" example:
>>
>> Hypothetically, we discover that when a client sends a zero value for
>> a latitude or longitude, we treat it as a "do not modify" instead of
>> actually setting the value to zero. This is not desired behaviour,
>> since there do exist legal lat/longs at the zero values (even if some
>> of them are very cold). So we fix the behaviour. Previously, a client
>> that didn't wish to modify the values could simply sent them to zero
>> when sending a message. Now, if the client did the same thing they
>> would wipe out existing lat/long values unintentionally. So, this fix
>> is not backward compatible.
>>
>> Even if we don't think anyone is using the previous behaviour, we
>> can't assume that. People don't have to ask permission of the TC team
>> to use the software or inform us that they are doing so. They don't
>> have to tell us about the clients they might have privately written
>> againt the API either.
>>
>> Another bugfix example:
>>
>> Hypothetically, we discover that when a client sends a zero value for
>> a longitude, we throw a divide-by-zero error and return a 500 or
>> crash. This is undesireable and we fix it to properly store the value
>> instead. A client can't claim that "crash the server" or "get 500s"
>> are legitimate conversations, so this is a backward compatible fix. No
>> correctly-operating client will fail in the presence of the new
>> behaviour. We do, however, need to make sure we update the patch
>> version, though. A clever client may have discovered that old versions
>> crash on zero longitude and it can query the (new) /version endpoint
>> to get the patch number to ensure that the client is well-behaved even
>> for older servers.
>>
>> Do these scenarios match what you're thinking of, when you say
>> "backward compatible"?
>>
>> On Thu, Oct 19, 2017 at 4:01 PM, Jeremy Mitchell <mi...@gmail.com>
>> wrote:
>> > 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 <al...@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.butts@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 <al...@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 <
>> mitchell852@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 <alficles@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 <
>> >> >> mitchell852@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.butts@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 <
>> neuman@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) <
>> >> >> >> >> > efriedri@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
>> >> >> >> >> > >
>> >> >> >> >> > >
>> >> >> >> >> >
>> >> >> >> >>
>> >> >> >>
>> >> >>
>> >>
>>

Re: Traffic Ops API Semantic Versioning

Posted by Jeremy Mitchell <mi...@gmail.com>.
chris,

the signing_algorithm thing does sound like a breaking change and sounds
like it could warrant the move from 1.2 to 2.x...

do bug fixes qualify as breaking changes?...hmm...i really hate to think
that simple bug fixes would require a major version upgrade but i see your
point.

It just feels to me like the TO API is a first class citizen of TC (or soon
will be) and like other TC components, it's version should follow along.

Just my 2 cents. I know others feel like this could simplify a lot of
things across components but I'll let them speak for themselves.

Jeremy

On Thu, Oct 19, 2017 at 5:03 PM, Chris Lemmons <al...@gmail.com> wrote:

> I think we can reasonably define "backwards-compatible change" to mean
> "a client of the prior version can communicate with the future version
> and all it's legitimate messages and sequences thereof are understood
> to mean the same as they did in the prior version". We can reasonably
> expect clients to ignore fields they do not understand in a response.
>
> Some examples:
>
> We add a new endpoint. This is backward compatible, because an old
> client won't know to communicate with it.
>
> We add a field to an existing endpoint. For a read-only endpoint, this
> is backward compatible. If the field is required on a post/put,
> however, it would not be. Likewise, if the server assumes a "zero
> value" instead of "not modified" on a post/put, that would also be not
> backward compatible. If the field can be omitted, and the field isn't
> modified on the server when it isn't present, it is backward
> compatible.
>
> A more concrete example:
>
> In the URI Signing PR, we change the underlying database value from
> "signed, boolean" to "signing_algorithm, varchar". Previously, the
> "signed" boolean meant "using url_sig". Now that we're trying to add
> "uri_signing" as an option, boolean doesn't make sense. But to
> mitigate the change, we're leaving the existing API field "signed" as
> a boolean that means "using url_sig".
>
> This is still not quite backward compatible, though. A client that
> knows nothing of the new "signingAlgorithm" field can read a DS that
> has "signed == false" and update it to "signed == true", then try to
> undo it's change by reverting to what it used to be "signed == false".
> For the old server version, this was a correct "undo" step. For the
> new server version, this step can potentially change a DS from
> "signingAlgorithm == uri_signing" to "signingAlgorithm == none". Since
> the meaning of this sequence of messages is different, the change is
> not backward compatible.
>
> A "bugfix" example:
>
> Hypothetically, we discover that when a client sends a zero value for
> a latitude or longitude, we treat it as a "do not modify" instead of
> actually setting the value to zero. This is not desired behaviour,
> since there do exist legal lat/longs at the zero values (even if some
> of them are very cold). So we fix the behaviour. Previously, a client
> that didn't wish to modify the values could simply sent them to zero
> when sending a message. Now, if the client did the same thing they
> would wipe out existing lat/long values unintentionally. So, this fix
> is not backward compatible.
>
> Even if we don't think anyone is using the previous behaviour, we
> can't assume that. People don't have to ask permission of the TC team
> to use the software or inform us that they are doing so. They don't
> have to tell us about the clients they might have privately written
> againt the API either.
>
> Another bugfix example:
>
> Hypothetically, we discover that when a client sends a zero value for
> a longitude, we throw a divide-by-zero error and return a 500 or
> crash. This is undesireable and we fix it to properly store the value
> instead. A client can't claim that "crash the server" or "get 500s"
> are legitimate conversations, so this is a backward compatible fix. No
> correctly-operating client will fail in the presence of the new
> behaviour. We do, however, need to make sure we update the patch
> version, though. A clever client may have discovered that old versions
> crash on zero longitude and it can query the (new) /version endpoint
> to get the patch number to ensure that the client is well-behaved even
> for older servers.
>
> Do these scenarios match what you're thinking of, when you say
> "backward compatible"?
>
> On Thu, Oct 19, 2017 at 4:01 PM, Jeremy Mitchell <mi...@gmail.com>
> wrote:
> > 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 <al...@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.butts@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 <al...@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 <
> mitchell852@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 <alficles@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 <
> >> >> mitchell852@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.butts@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 <
> neuman@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) <
> >> >> >> >> > efriedri@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
> >> >> >> >> > >
> >> >> >> >> > >
> >> >> >> >> >
> >> >> >> >>
> >> >> >>
> >> >>
> >>
>

Re: Traffic Ops API Semantic Versioning

Posted by Chris Lemmons <al...@gmail.com>.
I think we can reasonably define "backwards-compatible change" to mean
"a client of the prior version can communicate with the future version
and all it's legitimate messages and sequences thereof are understood
to mean the same as they did in the prior version". We can reasonably
expect clients to ignore fields they do not understand in a response.

Some examples:

We add a new endpoint. This is backward compatible, because an old
client won't know to communicate with it.

We add a field to an existing endpoint. For a read-only endpoint, this
is backward compatible. If the field is required on a post/put,
however, it would not be. Likewise, if the server assumes a "zero
value" instead of "not modified" on a post/put, that would also be not
backward compatible. If the field can be omitted, and the field isn't
modified on the server when it isn't present, it is backward
compatible.

A more concrete example:

In the URI Signing PR, we change the underlying database value from
"signed, boolean" to "signing_algorithm, varchar". Previously, the
"signed" boolean meant "using url_sig". Now that we're trying to add
"uri_signing" as an option, boolean doesn't make sense. But to
mitigate the change, we're leaving the existing API field "signed" as
a boolean that means "using url_sig".

This is still not quite backward compatible, though. A client that
knows nothing of the new "signingAlgorithm" field can read a DS that
has "signed == false" and update it to "signed == true", then try to
undo it's change by reverting to what it used to be "signed == false".
For the old server version, this was a correct "undo" step. For the
new server version, this step can potentially change a DS from
"signingAlgorithm == uri_signing" to "signingAlgorithm == none". Since
the meaning of this sequence of messages is different, the change is
not backward compatible.

A "bugfix" example:

Hypothetically, we discover that when a client sends a zero value for
a latitude or longitude, we treat it as a "do not modify" instead of
actually setting the value to zero. This is not desired behaviour,
since there do exist legal lat/longs at the zero values (even if some
of them are very cold). So we fix the behaviour. Previously, a client
that didn't wish to modify the values could simply sent them to zero
when sending a message. Now, if the client did the same thing they
would wipe out existing lat/long values unintentionally. So, this fix
is not backward compatible.

Even if we don't think anyone is using the previous behaviour, we
can't assume that. People don't have to ask permission of the TC team
to use the software or inform us that they are doing so. They don't
have to tell us about the clients they might have privately written
againt the API either.

Another bugfix example:

Hypothetically, we discover that when a client sends a zero value for
a longitude, we throw a divide-by-zero error and return a 500 or
crash. This is undesireable and we fix it to properly store the value
instead. A client can't claim that "crash the server" or "get 500s"
are legitimate conversations, so this is a backward compatible fix. No
correctly-operating client will fail in the presence of the new
behaviour. We do, however, need to make sure we update the patch
version, though. A clever client may have discovered that old versions
crash on zero longitude and it can query the (new) /version endpoint
to get the patch number to ensure that the client is well-behaved even
for older servers.

Do these scenarios match what you're thinking of, when you say
"backward compatible"?

On Thu, Oct 19, 2017 at 4:01 PM, Jeremy Mitchell <mi...@gmail.com> wrote:
> 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 <al...@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 <ro...@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 <al...@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 <mitchell852@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 <al...@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 <
>> >> mitchell852@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.butts@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 <ne...@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) <
>> >> >> >> > efriedri@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
>> >> >> >> > >
>> >> >> >> > >
>> >> >> >> >
>> >> >> >>
>> >> >>
>> >>
>>

Re: Traffic Ops API Semantic Versioning

Posted by Jeremy Mitchell <mi...@gmail.com>.
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 <al...@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 <ro...@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 <al...@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 <mitchell852@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 <al...@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 <
> >> mitchell852@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.butts@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 <ne...@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) <
> >> >> >> > efriedri@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
> >> >> >> > >
> >> >> >> > >
> >> >> >> >
> >> >> >>
> >> >>
> >>
>

Re: Traffic Ops API Semantic Versioning

Posted by Chris Lemmons <al...@gmail.com>.
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 <ro...@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 <al...@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 <mi...@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 <al...@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 <
>> mitchell852@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.butts@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 <ne...@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) <
>> >> >> > efriedri@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
>> >> >> > >
>> >> >> > >
>> >> >> >
>> >> >>
>> >>
>>

Re: Traffic Ops API Semantic Versioning

Posted by Robert Butts <ro...@gmail.com>.
@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 <al...@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 <mi...@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 <al...@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 <
> mitchell852@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.butts@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 <ne...@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) <
> >> >> > efriedri@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
> >> >> > >
> >> >> > >
> >> >> >
> >> >>
> >>
>

Re: Traffic Ops API Semantic Versioning

Posted by Chris Lemmons <al...@gmail.com>.
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 <mi...@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 <al...@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 <mi...@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.butts@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 <ne...@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) <
>> >> > efriedri@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
>> >> > >
>> >> > >
>> >> >
>> >>
>>

Re: Traffic Ops API Semantic Versioning

Posted by Jeremy Mitchell <mi...@gmail.com>.
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 <al...@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 <mi...@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.butts@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 <ne...@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) <
> >> > efriedri@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
> >> > >
> >> > >
> >> >
> >>
>

Re: Traffic Ops API Semantic Versioning

Posted by Chris Lemmons <al...@gmail.com>.
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 <mi...@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 <ro...@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 <ne...@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) <
>> > efriedri@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
>> > >
>> > >
>> >
>>

Re: Traffic Ops API Semantic Versioning

Posted by Jeremy Mitchell <mi...@gmail.com>.
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 <ro...@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 <ne...@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) <
> > efriedri@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
> > >
> > >
> >
>

Re: Traffic Ops API Semantic Versioning

Posted by Robert Butts <ro...@gmail.com>.
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 <ne...@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) <
> efriedri@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
> >
> >
>

Re: Traffic Ops API Semantic Versioning

Posted by Dave Neuman <ne...@apache.org>.
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) <
efriedri@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
>
>