The Proposal
Introduce support for the following additional fields:
deprecatedSince: An optional field that complements the ‘deprecated’ field on OpenAPI Specification 3.0. It is proposed that this field be used to provide information on the API version this deprecation came into effect.
since: An optional field that allow API contracts to declare the API version on which a specific schema, parameter or operation was introduced.
Justification
This information is critical to developers integrating with an API and helps them keep their integrations in sync with the latest releases.
Proposed specification changes
Introduce optional ‘deprecatedSince’, and ‘since’ fields that would have a string data type and format specifier to support semantic versioning (x.y.z)
The new definitions of the Operation, Schema and Parameter object with these proposed additions is as below.
The proposed fields are as follows:
Operation Object
Field Name | Type | Description
-- | -- | --
deprecatedSince | string | An optional specifier that complements the ‘deprecated’ field. Used to indicate the API version on which this operation was deprecated.Follows semantic version.
It is proposed that this field be ignored if the ‘deprecated’: true is not present in the definition
Parameter object
Field Name | Type | Description
-- | -- | --
deprecatedSince | string | An optional specifier that complements the ‘deprecated’ field. Used to indicate the API version on which this parameter was deprecated. Follows semantic version.
It is proposed that this field be ignored if the ‘deprecated’: true is not present in the definition
since | string | An optional specifier to indicate the API version on which this parameter was introduced.
Schema Object
Field Name | Type | Description
-- | -- | --
deprecatedSince | string | An optional specifier that complements the ‘deprecated’ field. Used to indicate the API version on which this schema field was deprecated.Follows semantic version.
It is proposed that this field be ignored if the ‘deprecated’: true is not present in the definition
Paging @philsturgeon, who is looking at deprecation in the context of JSON [Hyper-]Schema
Hey @sekharbans. I would be really interested in understanding the use-case for deprecatedSince.
Something I like about the Sunset header (for deprecating endpoints) is that it has one option: the date it will be deprecated. If that date is in the past, then you have your "since" answer: that field should no longer be used, because its supposed to have been removed already. Panic!
If we're talking API versions instead of dates, does it matter? If I have schema 1.0.0 and then I have 1.3.0 and I suddenly notice that it's deprecated in 1.3.0, do I really care if it was deprecated in 1.1.0 or 1.2.0? If it's deprecated its deprecated so stop using it :)
@philsturgeon The Sunset response header is still in draft. It indicates the upcoming retirement of a resource or an API and so it is not ideal for other API elements deprecation: fields, enumerated values, and behavior.
I don't think there is support for multiple Sunset headers to communicate multiple deprecations happening at a different time. The Sunset response header contains a single timestamp when a resource is expected to become unresponsive.
I was not proposing the Sunset header. It is certainly not appropriate for this. I was explaining "future date" as a method of deprecation seems clearly useful, but I am confused about the use-cases (and usefulness) of since.
@sekharbans would you mind editing out all of the (unchanged) property entries from the tables above? They don't really add anything, and make it unclear as to whether you think any existing text needs changing.
@MikeRalphson - altered as asked.
(Had included it for completeness)
Let’s say a developer integrated with an API 1.5 version and the latest API release is 1.7. A developer should have an easy way to find all of the operations, parameters etc added since ver 1.5 to understand the benefits of the latest release and to plan the integration work.
Sorry I don't understand.
It sounds like you're describing a changelog, and I don't know how knowing that a specific endpoint "has been deprecated since v1.5" would ever help me. It seems like a "I told you so" which does nothing to help the person looking at the specs.
Are you expecting tooling to aggregate information based on deprecatedSince values to programatically make a changelog of sorts, or... what is the idea?
Tooling for automated change logs would be a great use case.
In general, it is is useful to know when a specific operation / schema has been altered. Typically for complex enterprises with multiple integrations - it even helps with planning as @tanjav was pointing out.
If I'm building an automated changelog tool:
I read v1-5.yaml, foo is not deprecated.
I read v1-6.yaml, foo is deprecated.
I know that it was deprecated in v1.6.
You didn't explain anything any further you just said that it is useful. I'm trying to mine for information to find out how it is useful.
Going by your example:
Say you did NOT have to compare with v1-5.yaml (or by extension any earlier contract version). The current contract (say version 1.12 ) had information that foo was deprecated since v1.6.
And from planning point of view - a realization that the integration has been relying on a field that has been deprecated 6 versions back might cause a higher severity rank than an alteration recently introduced perhaps with the latest version release.
It would be impossible to build an automated changelog tool without having both versions to compare for changes, so if we're using this as a use-case then we've just invalidated our use case. We'd need to add addedSince, changedSince, etc, all keywords being added just to support something that OpenAPI-diff would be better suited to handle.
the integration has been relying on a field that has been deprecated 6 versions
Crikey, you'd be lucky for the field to still be there after _six versions_. That's probably already been deleted, which will probably be triggering all sorts of errors.
Would it not have been more useful to maybe look at one of the previous six versions that was released? Probably the 6th most recent version?
What workflow is happening when 6 versions are sneaking by and then you need to know just how much of a panic to be in?
Again this is why I mentioned Sunset, as it sets a date forward to let folks know that chance is coming, instead of giving them a huge fright months later when they actually notice.
My point is you would not even need a tool to compare multiple versions to find when a specific change was introduced - if the current contract _could give you_ that information.
So in summary - i guess there are two questions we have been deliberating on:
1) Is there a valid case around needing to know when a change was introduced? I guess we agree there may be a need
2) What is the easiest way to surface this information?
BTW I am no way disputing the need to provide a forward date to inform users about a future change.
My point is you would not even need a tool to compare multiple versions to find when a specific change was introduced - if the current contract could give you that information.
An OpenAPI specification is currently only able to describe the current contract. It tells you what type a property is, what the description is, what it expects to be valid, if it's deprecated, etc., but it cannot provide historical information on any of this.
To find changes over time you would always need to compare multiple versions.
- Is there a valid case around needing to know when a change was introduced? I guess we agree there may be a need
There is, and I feel like OpenAPI Diff covers that use case. If that tool needs more work, then that's what should be done.
- What is the easiest way to surface this information?
Again, OpenAPI Diff.
I do not think that the OpenAPI specification can switch from being descriptive of the current situation, to being descriptive of all past situations, like "event sourcing" for contracts.
You mentioned wanting to know when a change was introduced, but deprecations are not the only change. Changing types or formats or evolving contracts or anything else will always happen, and we cannot provide keywords that help describe those changes over time without really reimagining what OpenAPI is at a fundamental level.
Interesting note, this has been mentioned as part of https://github.com/OAI/OpenAPI-Specification/issues/782, with the keyword deprecatedVersion.
I also see no need for deprecatedSince as deprecated alone would suffice. since on the other hand may make sense.
And how about renaming the deprecated, which would be a boolean, to apiStatus or something along that line. This then would make it possible to make apiStatus an object, and
considering Java ApiGuardian here: https://github.com/apiguardian-team/apiguardian/blob/master/src/main/java/org/apiguardian/api/API.java, this would leave us with
paths:
/foo:
get:
apiStatus: // or just api:
since: 1.0.0-SNAPSHOT
status: EXPERIMENTAL
and so on. The same could then also be used on data types and properties, even parameters.
In addition, once could instruct code generators to only generate code for items that have been declared STABLE and DEPRECATED or even include the EXPERIMENTAL stuff.
Agreed that deprecatedSince has little value being added to the spec.
However, since would be immensely useful. Diffing two specs would be a cumbersome way of determining what minimum version of API provider is necessary to support a particular operation/schema/parameter. since would provide the ability, from a single spec, to show the consumer when something was introduced.
Use Case
In enterprise application development, consumers often will be looking at the latest version of API documentation, but may be running an older release. Adding since would allow the consumer to easily see if their instance of API provider supports what's in the latest spec/documentation, or what version they must upgrade to get that feature/data.
I'm not sure if you've spotted this floating around: https://tools.ietf.org/html/draft-dalal-deprecation-header-00 It's very new.
Let's let HTTP take care of this itself? Documentation is one way to do things, but REST is supposed to leverage the uniform interface to communicate as much as possible in the message itself, so if HTTP is getting since/version/date whatever then we don't really need OpenAPI to do it too.
Folks can add the deprecated header to their OpenAPI docs to let the documentation have visual identifiers for people. :clinking_glasses:
What do you think about allowing deprecated field to be object also. Instead of Sunset this can be based on aforementioned Deprecation header. Version can be inferred implicitly.
e.g.
deprecated: "2019-04-12" yields Deprecaton: version="v1" date="2019-04-12" header.
deprecated: true yields Deprecaton: version="v1" date="2019-04-12" as per [0]
[0] https://tools.ietf.org/html/draft-dalal-deprecation-header-00
The value of "Deprecation" response header field could consist of at
least 1 standard property: "date" or "version" as shown below.
Either of "version" or "date" is REQUIRED and both are also allowed.
The HTTP Deprecation header has Deprecation: true so dates are not always required, which is an exact match for deprecated: true in OAS.
As for dates, I still don't know that I'd need them recorded in the OAS document. If it's deprecated, it's deprecated, it doesn't matter how long ago it was deprecated you need to get on with switching away from it, and if you're getting runtime errors from your HTTP middlewares reporting the Sunset/Deprecation headers you'll know how urgent it is.
Remember, knowing when it was deprecated is less interesting than knowing when it will be _removed_, and deprecation doesn't tell us that, only the Sunset header does. Unless we add some sunset logic to OAS, I'd suggest deprecated: true and some human words in the description field.
There is some interesting stuff we can do to extend OAS deprecated with linking to a replacementOperationId if you'd like to chat about that over on #782?
Also, in the interest of combining conversations, let's chat about deprecation over there perhaps? This conversation has somewhat run its course, with HTTP headers speeding along and generally being a bit better equipped to handle this stuff. If you disagree lmk and we can reopen!