Protocol and Data Model Versioning

Protocol Versioning (work-in-progress proposal)

Key Points

  1. The use of the a version identifier within the the URI is a useful convention in some cases but does not fully address all the issues. There are real practical reasons for following the convention, but there is extremely little value in mandating the convention or directly prescribing it's use.
  2. The header approach is valid, but creation of a new header field is not required. I propose that a Link header with rel="implements" pointing to the version of the specification implemented is more than sufficient.
  3. Indicating the version in use is only part of the problem. We need to clearly deal with the upgrade transition, and how to signal to the client that an upgrade is required. There are several possible approaches:## "Hard Upgrade" -- basically, reject down-level requests with an error response## "In Place Upgrade" -- attempt to handle protocol upgrade in-place and as transparently as possible## "Upgrade Redirection" -- attempt to redirect clients to new the version
  4. Several mechanisms have emerged recently (Link and Prefer headers) that, when used with mechanisms that already exist within HTTP (Upgrade, 426 responses, etc) can provide a generalizable non-opensocial specific solution to what is a common, non-opensocial specific problem.

The ability for server and client implementions to clearly communicate which version of the OpenSocial specification a particular Service API and resource supports is critical. 

For the purpose of clearly identifying which version of the OpenSocial specification a particular application is implementing, a Web Link header referencing the base URI of the OpenSocial specification and using a rel attribute value of "implements" SHOULD be included within the HTTP request and response message.

For example, the Link would appear within the request:

GET /api/people/@me/@self HTTP/1.1
Host: example.org
Link: <http://opensocial.org/specs/3.0>; rel="implements"

And within the response:

HTTP/1.1 200 OK
Link: <http://opensocial.org/specs/3.0>; rel="implements"

A server MAY choose to implement additional conventions for identifying the current version, such as including a version indicator within the base URI of the Service API (e.g. http://example.org/v3/api/people).  Such conventions are considered out of scope.

Upgrade Indication and Transition

When a server implementation of an older version of the OpenSocial specification upgrades to a newer version, it has the responsibility to provide a clear mechanism for either continuing to support client applications using the old version or help clients migrate to the new.

Whether a server chooses to continue to support the old and new versions of the OpenSocial specification simultaneously is an implementation and business decision that is out of the scope of this specification.

However, when a server wishes to indicate to a client application that the server has been upgraded and that the old version of the API is no longer available, it SHOULD do so using an Upgrade Required response.

An "Upgrade Required Response" is an HTTP response that uses the 426 Upgrade Required status along with an "implements" Web Link.  For instance:

HTTP/1.1 426 Upgrade Required
Upgrade: OpenSocial/3.0
Connection: upgrade
Link: <http://opensocial.org/specs/3.0>; rel="implements"

Use of the 426 Upgrade Required response implies a complete cutover from one version of the specification to another.  Alternatively, a server can choose to migrate client applications incrementally, initially deploying the new version of the application side-by-side with the old.  Such a transition may or may not occur "in place", that is, requiring changes to the URI's a client uses to access the service.

For example, if a server currently exposes version 3.0 of the OpenSocial Profile Service at the URI "http://example.org/api/people", and it wishes to upgrade clients to a hypothetical version 3.1 in the future, without requiring clients to change the URIs they use to access the service, it can either continue to support the 3.0 clients transparently or perform an "in place" upgrade.

An example 3.0 client request:

GET /api/people/@me/@self HTTP/1.1
Link: <http://opensocial.org/specs/3.0>; rel="implements"

A server implementing the hypothetical 3.1 version of the OpenSocial spec can continue to respond as if it was a 3.0 implementation:

HTTP/1.1 200 OK
Link: <http://opensocial.org/specs/3.0>; rel="implements"
Content-Type: application/json

{... OpenSocial 3.0 data ...}

Or, it can perform an "in-place" upgrade:

HTTP/1.1 200 OK
Upgrade: OpenSocial/3.1
Connection: upgrade
Link: <http://opensocial.org/specs/3.1>; rel="implements"
Content-Type: application/json

{... OpenSocial 3.1 data ...}

Alternatively, the server MAY choose to deploy the new version with a new URI.

An example 3.0 client request:

GET /v3.0/api/people/@me/@self HTTP/1.1
Link: <http://opensocial.org/specs/3.0>; rel="implements"

An upgrade redirection from the server:

HTTP/1.1 301 Moved Permanently
Location: /v3.1/api/people/@me/@self HTTP/1.1
Upgrade: OpenSocial/3.1
Connection: upgrade
Link: <http://opensocial.org/specs/3.1>; rel="implements"

Client Upgrade Preferences

Implementors of client applications MAY use the Prefer HTTP Header within a request to indicate the preferred mechanism for upgrade handling.

This specification registers the following new Prefer header token values:

  • return-upgrade-required: Indicates that the client prefers the server to respond with a 426 Upgrade Required response when a protocol upgrade is required by the server.
  • upgrade-in-place: Indicates that the client prefers the server to attempt an in-place, transparent upgrade to a newer version of the protocol, as required.  The in-place-upgrade preference MAY include a preference value indicating the maximum allowed protocol version.  The asterisk (*) character may be used as a wildcard. For instance, "Prefer: upgrade-in-place=3." indicates that the client prefers an in-place-upgrade for any protocol version matching the pattern "3.*" (e.g. 3.1, 3.2, 3.3, etc).
  • upgrade-redirect: Indicates that the client prefers the server to use redirects when upgrading protocols.  If a redirect is not available, then the 426 Upgrade Required response is preferred.

These Preference tokens MAY be used together.

For example, a client can indicate to the server that it is capable of handling automatic in-place upgrade for any 3.* version of the specification but prefers use of the 426 Upgrade Required response for all other cases:

GET /api/people/@me/@self HTTP/1.1
Link: <http://opensocial.org/specs/3.1>; rel="implements"
Prefer: return-upgrade-required, upgrade-in-place=3.*

Or, for instance, a client can indicate that is is capable of handling automatic in-place upgrades for any 3.* version and prefers use of redirects for all other cases:

GET /api/people/@me/@self HTTP/1.1
Link: <http://opensocial.org/specs/3.1>; rel="implements"
Prefer: upgrade-redirect, upgrade-in-place=3.*

Data Model / Format Versioning (work-in-progress proposal)

Key Points

  1. Data Model and Format Versioning information can be expressed within the data format (e.g. a field within the document) or externally via media types... 
  2. Both have their respective benefits and limitations.. there's no reason we can't do both.
  3. It doesn't have to be that difficult.

First... let's introduce an OpenSocial Media Type to represent the OS 3.x Data Model. 

JSON Data Model

application/vnd.opensocial.data.3+json

XML Data

application/vnd.opensocial.data.3+xml

The ".3" portion of the Media Type indicates the major version of the OpenSocial Format. The assumption is that all minor versions would maintain fundamental data model and format compatibility within a single major (e.g. 3.2 would be backwards compatible with 3.1 and 3.0, etc) therefore we eliminate the need to mint a new media type for each minor update.The media type would be used within HTTP requests and responses to indicate the supported version.

For instance, if a client wishes to notify the server that it implements version 3.0 of the OS specification but will accept down-level versions of the data format if necessary, it can send the following request:

GET /api/people/@me/@self HTTP/1.1
Host: example.org
Link: <http://opensocial.org/specs/3.0>; rel="implements"
Prefer: upgrade-in-place=3.*
Accept: application/vnd.opensocial.data.3+json, application/vnd.opensocial.data.3+xml, application/json;q=0.5

A server examining this request can determine unambiguously what version of the OS protocol and data model the client supports and what the client's preferences are as far as data model and protocol behavior. If this request is sent to a downlevel (2.x) version server, the Link, Prefer and Accept headers are most likely to be ignored and a typical 2.x response would be generated – which is acceptable to the client given the construction of the request. If the server supports 3.x it will return an expected 3.x response. If the server happens to support a future hypothetical version (e.g. 4.x), then it can decide to either a) respond to the request as if it were 3.x, b) attempt to do an inline upgrade to 4.x and c) reject the request and ask the client to upgrade. 

Using a media type, however, only addresses part of the problem. It is often the case that data being processed can become disconnected from the request context (e.g. the media type is no longer available). It is helpful in such situations for the data format / model itself to directly indicate which version of the specification is supported. For this, I propose that we leverage the same "implements" link relation used in the Link header... within the XML serialization, this would manifest as an atom:link element, e.g. <link rel="implements" href="http://opensocial.org/specs/3.0" />. Within JSON, we need to get a bit creative since there currently are no defined standards for representing links in JSON; my suggestion based on general discussion would be use a "$rel" naming convention, e.g. "$implements":"http://opensocial.org/specs/3.0".

For example, within any OS 3.0 JSON serialization, it would be:

{
 "$implements":"http://opensocial.org/specs/3.0",
 "id":"example.org:...",
 "displayName":"Jane",
 ...
}

If multiple versions need to be specified, the value can be an array (e.g. "$implements":["...","..."] )

Gadget Spec XML Media Type

Section 8 of the Core Gadget spec document provides a rudimentary mechanism for specifying which version of the specification a gadget spec implements along with which versions of features. What the Core Gadget spec fails to do, however, is deal with versioning of the Gadget XML document format itself. At an absolute minimum, a MIME Media Type is required:

application/vnd.opensocial.gadget.3+xml

Embedded Experiences Document Media Type

The Embedded Experiences document media type should be updated to reflect both the versioning requirement and feedback provided by the IETF Mime Media Types mailing list suggesting that all OpenSocial related Mime types use the vnd.opensocial convention. This would change the EE Doc media types from "application/embed+xml" and "application/embed+json" to:

application/vnd.opensocial.embed.3+xml

and

application/vnd.opensocial.embed.3+json

Message Bundle Document Media Type

Optionally, as a best practice, we should define media types for all the various document types we have, including the Message Bundle defined in the Core Gadget spec. 

appication/vnd.opensocial.message.3+xml

Template Library Document Media Type

Additionally, we should have a media type for the Template Library format...

application/vnd.opensocial.templates.3+xml