I'm not totally following. Currently we get component release versions like 3.0.0-<commit #>.<commit hash> for the various rpms. Are you saying we'd make the TO release version be 1.5-<commit #>.<commit hash> (if the current API version is 1.5)?
- Rawlin On Thu, Feb 14, 2019 at 1:18 PM Fieck, Brennan <brennan_fi...@comcast.com> wrote: > > Sure, but TO API v1 would only be implemented by TO v1 and TO API v2 only > implemented by TO v2. > ________________________________________ > From: Rawlin Peters <rawlin.pet...@gmail.com> > Sent: Thursday, February 14, 2019 12:59 PM > To: dev@trafficcontrol.apache.org > Subject: Re: [EXTERNAL] Re: Traffic Ops API versioning issues > > Scripts written against TO API v1 should always work against TO API > v1, no matter if Traffic Ops is v2.2, v3.0, or v4.0. The API version > shouldn't have to match the version of the software that implements > said API. > > - Rawlin > > On Thu, Feb 14, 2019 at 12:36 PM Fieck, Brennan > <brennan_fi...@comcast.com> wrote: > > > > The idea with regard to breaking changes is that a breaking change in > > the API is seen as a breaking change in TO - so scripts written against > > TO v1 should always work with TO v1. When TO v2 is released, after > > exiting your time machine, you shouldn't expect your v1 scripts to > > work with v2. > > ________________________________________ > > From: Rawlin Peters <rawlin.pet...@gmail.com> > > Sent: Thursday, February 14, 2019 10:53 AM > > To: dev@trafficcontrol.apache.org > > Subject: Re: [EXTERNAL] Re: Traffic Ops API versioning issues > > > > There is a lot of stuff to digest here, and I agree that the v1 API is > > desperately in need of a good v2. However, I'm not sure I agree that > > the API should be versioned alongside Traffic Ops. The API version > > should be separate from the Traffic Ops/Traffic Control release > > versions. We should do our best to not break a major API version, so > > in theory a script written against TO API v1 should always work with > > TO API v1. When TO API v2 is introduced, the script written against v1 > > would not be guaranteed to work against v2 (although, we should still > > support v1 for some time before deprecating in favor of v2). > > > > - Rawlin > > > > On Thu, Feb 14, 2019 at 8:07 AM Fieck, Brennan > > <brennan_fi...@comcast.com> wrote: > > > > > > I'd take it further, though in my opinion it shouldn't be done until > > > we're ready to do away with Perl entirely. > > > I've been working on this for a little bit, and I sorta wanted to make a > > > wiki page for a proposed API v2 design before sending it, but what the > > > heck. The conversation is here now. > > > > > > > > > I don't like the way our API is versioned. Let me be clear, it _should_ > > > be versioned, and the > > > versions _should_ be semantic, but it is my opinion that the API should > > > be versioned alongside > > > Traffic Ops rather than at its own pace. I've written essentially an > > > article on why this should be > > > the case, and it follows: > > > > > > ** TIMING ** > > > The first issue I should address is timing - this needn't happen > > > immediately. For the time being, I > > > think a radical change would be much more harmful than continuing along > > > our current versioning > > > scheme. This change should be implemented with the advent of what we > > > currently refer to as "API v2". > > > Presumably, at this time all of the Perl code has been removed and we are > > > looking to re-tool the API > > > to be more sensible and standards-conforming. It's a time when we'll > > > already be making big, breaking > > > changes. I personally would love for this to be ATC 4.0, but that may not > > > be a realistic goal. > > > > > > ** REDUNDANCY ** > > > The easiest to see - albiet simultaneously most trivial - issue with the > > > current API versioning > > > scheme is how every request path must start with '/api/1.x/'. This is > > > annoying, to be frank; > > > especially when one considers that the current plan for Traffic Ops is to > > > reduce it entirely to an > > > API, so literally every endpoint will have '/api/' in common. We _know_ > > > the endpoint we are trying > > > to query is an API endpoint because _all_ endpoints are API endpoints. > > > When we reach "API v2" the > > > '/api/' part of request paths will have lost all value entirely. > > > Even with that gone we are left with '/1.' (or '/2.' as the case may > > > become) as a common prefix, > > > again annoying although not totally useless in this case. However, the > > > vast majority of API > > > endpoints see no changes between minor versions, so really '/1.x' just > > > becomes a static, constant > > > prefix where 'x' is the latest version of the API. > > > In any case, versioning the API alongside Traffic Ops solves this problem > > > because our Traffic Ops > > > server(s) emit HTTP headers that name the server. Once Perl is gone, > > > we'll be free to use the HTTP > > > `Server:` header to name the server e.g. `Server: Traffic Ops/3.2.1`. At > > > this point, we could > > > either implement an `OPTIONS` method request at the server's root that > > > would just return some > > > headers - including `Server:` or just let people to a `GET` (or better > > > yet `HEAD`) request to > > > `/ping` and pull the server version out of the headers. The client then > > > has all the information it > > > needs to communicate effectively with the server. The alternative to this > > > within our current > > > versioning schema is to implement an unversioned API endpoint such that > > > we have a hundred `/api/1.x` > > > endpoints and one that has some other - or possibly no - prefix, or have > > > a versioned API version API > > > endpoint, which is confusing even just to say. > > > > > > ** TRAFFIC OPS _IS_ THE API ** > > > As mentioned previously, the endgame of our transition from Perl to Go is > > > that Traffic Portal is the > > > only UI for ATC - and in fact that's already somewhat true. That leaves > > > Traffic Ops as a database > > > and a REST API for interacting with said database. In fact, the database > > > is often referred to as its > > > own service: "ToDb", "Traffic Ops DB" etc. That means that we have the > > > single most important Traffic > > > Control component split in two - half of its functionality is versioned > > > sanely with Traffic Control > > > while the other half is versioned separately from anything else in the > > > world. That's crazy, because > > > if you have a program that only does two things, then surely a breaking > > > change to one of those > > > things means increasing its major version? If that's the case, then why > > > are we not versioning the > > > API alongside Traffic Ops? > > > It may be argued (incorrectly, in my opinion) that Traffic Ops does more > > > than serve an API to > > > interact with a database. It generates configuration files and system > > > images, it combines data and > > > does heavy processing on it. But really those things shouldn't be taken > > > into account in a versioning > > > scheme except insofar as they affect the experience of some user, > > > administrator, or application > > > interfacing with Traffic Ops. If the API responses don't change in form > > > or content, and if the > > > process of setting up or maintaining the application haven't changed, > > > then any code changes you've > > > made are a patch, not a version change. Traffic Ops does big things, but > > > at the end of the day it > > > all just boils down to API inputs and outputs as far as anything and > > > anyone else is concerned. > > > > > > ** CONFUSION ** > > > We currently live in a world where I can run a script using the Traffic > > > Ops API that works perfectly > > > fine against Traffic Ops version 3.2.1, but then if I again test it > > > against version 3.2.1 at some > > > point in the future it breaks because breaking changes were made in the > > > API. It's easy to say, "oh, > > > that just means that when we make breaking API changes we should > > > increment the version > > > appropriately," but realize that this _is versioning the API alongside > > > Traffic Ops_. If we're not > > > doing that, we're saying there is unpredictability with the behavior of > > > our system within releases, > > > and if we _are_ doing that then the only difference between the API > > > version and the Traffic Ops > > > version is that the API version is confusingly behind by about 2 major > > > revisions. It should just be > > > the same for simplicity's sake. > > > > > > ** THE API "PROMISE" ** > > > The single most common argument I hear in favor of our current API > > > versioning scheme is "well we've > > > said an API version 1.x behaves in this way, and so we must uphold that > > > promise to the user base". > > > Not only do we routinely break that promise already, > > > (e.g. PR #3110 [https://github.com/apache/trafficcontrol/pull/3110]) but > > > I'm certainly not > > > suggesting that we don't uphold this promise. Yes, this does mean that > > > making breaking API changes > > > in TO would require a new major release and adding features/fields to the > > > API would require a new > > > minor release. I don't see that as a big deal, especially if implemented > > > at the time I'm suggesting > > > when we'd be re-designing the API - and it does sorely need to be > > > redesigned. > > > > > > * The API Needs to be Redesigned * > > > I'm going to go down this rabbit hole for a second, if you're already > > > convinced the TO API needs a > > > re-design then feel free to skip this section. I'm not going to touch on > > > any problems caused in the > > > API as currently implemented by the use of a standalone API version - > > > that's what the entire article > > > is for. > > > Currently, our API currently has three huge problems: > > > > > > 1. Rampant oversaturation of endpoints > > > We have a systemic issue of re-implementing behaviour in multiple > > > endpoints. This is due in part > > > to a lack of good documentation - so developers aren't aware of > > > the endpoints available to them > > > - and partly because of the "Mojolicious Mindset" that plagues > > > our oldest endpoints. The > > > "Mojolicious Mindset" refers to the use of URL path fragments as > > > request parameters, e.g. > > > '/users/{{ID}}' instead of/in addition to '/users?id={{ID}}'. > > > From the perspective of someone > > > who is just writing the back-end for these endpoints, there's no > > > clear advantage to one over the > > > other except that the former seems to more clearly reflect the > > > intent of requesting a specific > > > object whereas the latter could be seen as more of a "filter" on > > > a larger collection. That's not > > > incorrect, necessarily, but the two are totally separate request > > > paths, so having '/users' and > > > '/users/{{ID}}' means documenting two endpoints instead of one, > > > and it means two lines in the > > > route definitions, and it means two seperate handlers instead of > > > one (albiet a more complex > > > one). > > > Consider also that we have all of the following endpoints for > > > manipulating Cache Groups: > > > > > > * /api/1.x/cachegroup/{{parameter ID}}/parameter > > > * /api/1.x/cachegroup_fallbacks > > > * /api/1.x/cachegroupparameters > > > * /api/1.x/cachegroupparameters/{{ID}}/{{parameter ID}} > > > * /api/1.x/cachegroups > > > * /api/1.x/cachegroups/{{ID}} > > > * /api/1.x/cachegroups/{{ID}}/deliveryservices > > > * /api/1.x/cachegroups/{{ID}}/parameters > > > * /api/1.x/cachegroups/{{ID}}/queue_updates > > > * /api/1.x/cachegroups/{{ID}}/unassigned_parameters > > > * /api/1.x/cachegroups/{{parameter ID}}/parameter_available > > > * /api/1.x/cachegroups_trimmed > > > > > > These could all be collapsed neatly into one or two endpoints, but > > > were instead implemented > > > separately for whatever reason(s) > > > (see Issue #2934 > > > [https://github.com/apache/trafficcontrol/issues/2934] for details). > > > > > > 2. Improper/Non-existent standards conformity > > > We have requests that should be read-only that make server-side > > > state changes (Issue #3054 > > > [https://github.com/apache/trafficcontrol/issues/3054]), we have > > > endpoints returning success > > > responses on failure (Issue #3003 > > > [https://github.com/apache/trafficcontrol/issues/3003]) and > > > our "CRUDER" has failed us. `PUT` should be used to _create_ > > > objects (or possibly update them by > > > creating an alternative representation with the same identifiying > > > information) but is instead > > > used as the primary "edit this" method. `POST` is for processing > > > entities in a data payload, but > > > is instead used for object creation. `PATCH` languishes, totally > > > unimplemented. These problems > > > are systemic and stem partially from the "Mojolicious Mindset" > > > whereby new functionality is > > > introduced into the API by first considering what request method > > > is appropriate and then > > > deciding on a request path that names the operation being done. > > > Request methods are meant to be > > > the different ways in which a client interacts with a resource on > > > the server, and thus the > > > resources themselves should be considered primary. The "CRUDER" > > > hampers this mindset, because it > > > makes treating payloads and query parameters generic and isn't > > > receptive to injection of new > > > behaviour. > > > The "CRUDER" is a great innovation, to be sure, as it saves us > > > quite a bit of time and prevents > > > duplicating code, but the problem it solves is an emergent > > > property of of API problem #1 above. > > > With fewer endpoints we'd have much more specific handling, and > > > the need for and advantages of > > > the "CRUDER" will vanish. > > > > > > 3. Needing multiple queries to obtain a single piece of information > > > This issue is pretty deeply rooted, and is related to the way our > > > database is structured. But > > > that's part of the problem - an API needn't replicate the > > > database, and is therefore free from > > > some of the constraints that bind a database. > > > The way things are now, in order to e.g. create a server > > > definition I must make several > > > preliminary requests to determine the integral, unique, > > > non-deterministic identifiers of other > > > objects. I think we all agree that ideally these integral IDs > > > would have no part in the output > > > of the API, and many people I've spoken to would support wiping > > > them from the database entirely > > > given enough time and manpower. > > > > > > ________________________________________ > > > From: Robert Butts <r...@apache.org> > > > Sent: Wednesday, February 13, 2019 6:11 PM > > > To: dev@trafficcontrol.apache.org > > > Subject: Re: [EXTERNAL] Re: Traffic Ops API versioning issues > > > > > > >It doesn't seem like the idea of full TO API SemVer was ever fully > > > discussed and voted on > > > > > > >Since it seems like we never truly committed to SemVer with minor > > > >versions > > > for the TO API > > > > > > There was consensus: > > > https://lists.apache.org/thread.html/8f8a850c68424021a0fe06967894383a24e463f1b0cee4d652d04590@%3Cdev.trafficcontrol.apache.org%3E > > > https://lists.apache.org/thread.html/1a42a2192a81fc4d76639ccd10761b6b73c31345a63715bb8aa86e4e@%3Cdev.trafficcontrol.apache.org%3E > > > > > > We didn't do an official [VOTE], but we rarely do that as a project, > > > unless > > > there's difficulty reaching unofficial consensus. That said, there's > > > nothing stopping another discussion or vote, if we want to change things. > > > > > > >as long as we set the expectations for the user > > > > > > That's precisely my point. We can always say "we set the expectations, > > > it's > > > the user's fault for misreading, or misunderstanding, or not noticing a > > > changelog." It's not about fault, it's about providing a better user > > > experience. > > > > > > >that support has to be baked into traffic_ops_golang such that it's easy > > > and maintainable to support tons of minor versions. If we keep heading > > > down > > > our current path we are going to be left with a giant mess. > > > > > > I don't think anyone disagrees. Traffic Ops versioning has had > > > considerable > > > technical debt for some time now. We just haven't been willing to spend > > > the > > > time to fix it. I agree, that needs to change. > > > > > > I'd also like to note, there's another option: code generation. We can > > > keep > > > the structs and handlers largely the same, and generate the "duplicate" > > > code when a new minor version is added. There's a strong argument that > > > this > > > is the "idomatic" way to solve this problem, for the Go language. I > > > personally feel Reflection is better here. But, I wanted everyone to be > > > aware that's an option, if the consensus is that it's the best option. In > > > a > > > nutshell, we could generate code with a script (with a spectrum of > > > precision and complexity, from `cp && sed` to parsing the AST), and > > > `routes.go` would have a `//go:generate` header. For examples, see: > > > > > > https://blog.golang.org/generate > > > https://godoc.org/golang.org/x/tools/cmd/stringer > > > > > > I did some prototyping of that approach, if anyone is interested, just let > > > me know and I can provide examples of what that would look like. > > > > > > > > > On Wed, Feb 13, 2019 at 5:09 PM Rawlin Peters <rawlin.pet...@gmail.com> > > > wrote: > > > > > > > On Wed, Feb 13, 2019 at 1:20 PM Gray, Jonathan > > > > <jonathan_g...@comcast.com> wrote: > > > > > > > > > > I'm +1 on keeping full API SemVer. > > > > > > > > > On 2/13/19, 12:16 PM, "Robert Butts" <r...@apache.org> wrote: > > > > > > > > > > We would be abandoning Semantic Versioning. > > > > > > > > This is why I wanted to open this up for broader discussion within the > > > > community. It doesn't seem like the idea of full TO API SemVer was > > > > ever fully discussed and voted on (at least not to my knowledge), > > > > which is why I haven't been abiding by it myself or enforcing it upon > > > > other TO API devs either. If we're going to truly commit to SemVer > > > > with minor versions for TO API then we should fully understand the > > > > cost vs utility of doing so. Also, SemVer doesn't have to be an "all > > > > or nothing" thing, as we currently choose to ignore the "patch" > > > > version for the TO API. We could also choose to ignore the minor > > > > version and just focus on the most important aspect of SemVer which is > > > > not introducing backwards-incompatible changes in the same major > > > > version. > > > > > > > > Since it seems like we never truly committed to SemVer with minor > > > > versions for the TO API, traffic_ops_golang wasn't designed to easily > > > > support minor versions. So if we're going to truly commit to SemVer > > > > with minor versions for TO API, then that support has to be baked into > > > > traffic_ops_golang such that it's easy and maintainable to support > > > > tons of minor versions. If we keep heading down our current path we > > > > are going to be left with a giant mess. > > > > > > > > The only way I can get behind supporting the "minor version promise" > > > > is if we have a way to basically just tag fields as introduced in a > > > > specific API version, with just a single struct per resource and a > > > > single handler per major version of an endpoint. We should only > > > > require a single implementation of an endpoint per major version. If a > > > > custom JSON parser allows us to do that, then that's great. Without > > > > that, I don't think supporting the "minor version promise" is even a > > > > viable option. > > > > > > > > A lot of those scenarios around user confusion due to supporting just > > > > a major version are not really an issue as long as we set the > > > > expectations for the user. I.e.: > > > > - clients should request v1 > > > > - as the v1 API is enhanced in a backwards-compatible manner, clients > > > > will begin to see new fields in the server responses > > > > - if a client wants to modify a resource, they will typically do a GET > > > > on the resource, modify the resource, then do a PUT back to the > > > > server. > > > > - in the GET response, if the client sees new fields, they can expect > > > > to modify those fields and see it reflected on the server. > > > > - if the client does NOT see new fields, then they cannot add fields > > > > and expect to see that reflected on the server > > > > - null values in optional fields will be interpreted by the server as > > > > whatever the default for that optional field is. So if the default for > > > > new optional field "foo" is 5, then a client sending `"foo": null` > > > > will be interpreted by the server as `"foo": 5`, and `"foo": null` > > > > should never have a different meaning than `"foo": 5` on the server. > > > > > > > > The advantage of just supporting the "major version promise": > > > > - jives better with Go's lack of metaprogramming > > > > - no custom JSON parser in Go required > > > > - less general overhead in development > > > > - only have to worry about breaking changes > > > > - no worrying about which fields belong to which minor versions > > > > - no extra API testing to make sure fields introduced in API v1.N > > > > aren't returned to v1.N-1 clients > > > > - don't have to update every single client in the repo with the new > > > > minor version every time a minor version is incremented (since clients > > > > would just specify the major version) > > > > > > > > So, as a community, we need to weigh these options and decide whether > > > > or not we want to take the "major version only" route or the "major > > > > plus minor version" route. Personally, I prefer the "major version > > > > only" route because it means less code, less overhead, less > > > > coordination, and less things to potentially go wrong. However, if a > > > > relatively small custom JSON parser is all we really need to > > > > reasonably support the "minor version promise", then I can't say I'm > > > > completely against that route either (just that I wouldn't prefer it). > > > > > > > > - Rawlin > > > >