-
Notifications
You must be signed in to change notification settings - Fork 890
Resource Versioning Profile #1333
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: gh-pages
Are you sure you want to change the base?
Changes from 8 commits
df9838a
e815ccd
c302a8c
84d4840
ea9c13c
9d9e263
9368cbc
d3c1d13
cac4baf
56bc05e
75659ce
2d5346e
c351d9c
3e4b67e
515aba9
0feddd6
b0a1e3d
f0d73db
a4329d5
7a352dc
9129eb2
ba9bf0b
6bc95be
1a1395d
e4adbd7
5c5b0f4
c82ecbe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
--- | ||
name: Resource Versioning | ||
short_description: | | ||
Defines a protocol for requesting versioned resources via a JSON:API | ||
server. | ||
|
||
extended_description: | | ||
# Overview | ||
JSON:API servers that are capable of tracking a record of changes to a | ||
resource object may afford the capability of requesting a resource object | ||
as it existed in a prior or successive state. This capability is herein | ||
defined as _resource versioning_. | ||
|
||
This profile establishes a protocol for resource versioning by defining a | ||
query parameter and its semantics in order to identify arbitrary revisions | ||
of a resource and how a server should interpret this query parameter. | ||
|
||
minimum_jsonapi_version: 1.0 | ||
minimum_jsonapi_version_explanation: | ||
|
||
discussion_url: https://www.drupal.org/project/issues/jsonapi | ||
|
||
editors: | ||
- name: Gabriel Sullice | ||
email: gabriel@sullice.com | ||
- name: Mateu Aguiló Bosch | ||
email: mateu.aguilo.bosch@gmail.com | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
website: https://humanbits.es | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- name: Wim Leers | ||
email: work@wimleers.com | ||
website: https://wimleers.com | ||
|
||
categories: | ||
- Resource Versioning | ||
--- | ||
|
||
# Concepts | ||
Resources on a server may undergo changes and the state of a resource with an | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that by "the state […] may be accessible", you mean that each state may be individually accessible? |
||
arbitrary number of changes may be accessible. It is often useful to retrieve | ||
resources as they existed at the time of their creation or in various states of | ||
change for editorial or archival purposes. This profile establishes a protocol | ||
for accessing resources in those various states. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is talking about previous states, for archival/history purposes. I think this should also explicitly state next states, i.e. drafts that are actively being worked on, or perhaps need to go through legal review, or are ready but simply aren't yet live because they're scheduled to be published in the future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I agree that this could be clarified, but I did not mean previous as you are interpreting it. Even future revisions were created previously to now. They may not be the default version yet, but that does not mean that the revision itself was created in the future. |
||
|
||
For the purpose of understanding this profile, it is helpful to establish a | ||
vocabulary for describing various possible states of a resource. | ||
|
||
A _revision_ is to be understood as an identifiable state of a resource after | ||
its creation or after some number of changes. | ||
|
||
A _version_ is to be understood as a revision of a resource that is available, | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
or was previously available, without any version negotiation. In other words, as | ||
a revision that is or was the default revision of a resource. | ||
|
||
A _working copy_ is the revision to which new changes can be made or to which | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This term is specifically borrowed from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wow, I can't believe that I didn't already do that. |
||
they will be applied. Colloquially, a working copy is often thought of as the | ||
"tip" of a version history. | ||
|
||
For example, a resource which existed as a draft and underwent multiple changes | ||
before the resource was published may have many revisions. Only the published | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
revision would be considered a version. The revisions prior to first version | ||
would have been known as the working copy as each one was created. | ||
|
||
If the version is then checked out for further changes (which may or may not be | ||
published) each new revision becomes the working copy. | ||
|
||
Sophisticated servers may support multiple versions of a resource as well as | ||
multiple working copies of a resource (e.g., to support multiple | ||
languages or within a version control system which supports multiple branches). | ||
|
||
This profile creates a standard for JSON:API to support these diverse versioning | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "these diverse" refers to both the "multiple versions" and "multiple working copies" in the preceding paragraph. Therefore I think it should be "diverse revisioning schemes", not "diverse versioning schemes"? (Because "versioning" refers only to versions, not to working copies.) |
||
schemes. | ||
# Query Parameter | ||
|
||
## Usage | ||
|
||
An endpoint **MAY** support a `resource_version` query parameter to allow a | ||
client to indicate which version(s) of a resource should be returned. | ||
|
||
If an endpoint does not support the `resource_version` parameter, it **MUST** | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
respond with `400 Bad Request` to any requests that include it. | ||
|
||
If an endpoint supports the `resource_version` parameter and a client supplies | ||
it: | ||
|
||
- The server’s response **MUST** contain the most appropriate version of the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think "the most appropriate" is unnecessarily vague. Can't we change |
||
resource requested. | ||
- The server **MUST NOT** include a version of a resource inappropriate for the | ||
requested version. | ||
- The server **MUST** respond with `404 Not Found` if an appropriate version of | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
the resource requested cannot be located. | ||
|
||
> Note: This means that a server should not provide "fallbacks" unless the | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
> behavior is well defined by the version negotiation mechanism (see below). | ||
> These rules apply to individual and collection endpoints alike. | ||
|
||
## Format | ||
|
||
The value of the `resource_version` parameter **MUST** be a colon-separated | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(U+003A COLON, “:”) string. The first segment of the string **SHOULD** be | ||
interpreted as an identifier for a _version negotiation mechanism_. A version | ||
negotiation mechanism defines how a server will locate an appropriate resource | ||
version. Subsequent segments of the string **SHOULD** be interpreted as version | ||
negotiation arguments for the preceding mechanism. Collectively, this query | ||
parameter value is known as the _version identifier_. | ||
|
||
> Note: For example, a server may support both ID-based and time-based | ||
> mechanisms for requesting a resource version. The former mechanism would be | ||
> useful for comparing versions and the latter could be useful for requesting a | ||
> resource as it existed at an arbitrary point in time. This profile does not | ||
> attempt to define every possible mechanism for versioning resources. | ||
|
||
``` | ||
version-identifier | ||
_______|_________ | ||
/ \ | ||
?resource_version=rel:latest-version | ||
\_/ \____________/ | ||
| | | ||
version-negotiator | | ||
version-argument | ||
``` | ||
|
||
## Server Responsibilities | ||
|
||
<a id="bad-version-negotiator"></a>A server **MUST** respond with `400 Bad Request` if a version negotiator is not | ||
supported. In this case, an error object that includes a `type` link to | ||
`https://jsonapi.org/profiles/drupal/resource-versioning/#bad-version-negotiator` | ||
**MUST** be included in the response document. | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
<a id="bad-version-argument"></a>If a server cannot process the given version argument for the given negotiation | ||
mechanism, it **MUST** respond with a `400 Bad Request`. In this case, an error | ||
object that includes a `type` link to | ||
`https://jsonapi.org/profiles/drupal/resource-versioning/#bad-version-argument` | ||
**MUST** be included in the response document. | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
If a server is able to process the version argument but an appropriate version | ||
cannot be located, the server **MUST** respond with a `404 Not Found`. | ||
|
||
# Version Negotiators | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Design feedback/interoperable implementations review requirement] If I'm understanding correctly, each server implementation can define its own version negotiators, with multiple servers using the same negotiator name in different ways (and no central registry). That seems not great for interoperability. It would also seem to mean that no other version negotiators can ever be standardized as part of this profile, because they could conflict with existing implementations. Is that really what you want? My gut instinct would be to make this profile's spec the canonical list of all legal version negotiators. Then, you can add more over time to this spec as they're requested. To support people who really need to use a version negotiator that isn't part of your profile, you could have some set of negotiator names/schemes/namespaces that are allowed to have implementation-specific meanings. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc: @wimleers cause it's his inbox that I suggested too 😛 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm OK with that. However I still think that doc curies offer a lower barrier of entry. One could document the new crazy negotiator in their blog and have the server implementation point to that, instead of adding it here. Many will just not go through the trouble to send their idea to some email addresses and be potentially blocked by them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess I wanted to discourage non-standard negotiators being used as a standard and keep them isolated. My feeling was that sending an email saying "hey, I'd like to add a negotiator like this..." doesn't seem like a super high barrier. In some ways, it's even less difficult than opening a PR. What if we add this:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @e0ipso, would that work? |
||
|
||
## ID-Based Version Negotiator | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
This profile establishes the `id` version negotiator. An `id`-based version | ||
identifier is composed of two segments—the `id` version negotiator and a single | ||
version argument. Any colons (U+003A COLON, “:”) present in the version | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should say that the version argument is an opaque string. |
||
identifier after the first occurrence **MUST** be interpreted as part of the | ||
single version argument and **MUST NOT** be interpreted as a segment delimiter. | ||
|
||
The resource version returned for any given version argument in an `id`-based | ||
version identifier **MUST NOT** change over time. | ||
|
||
> Note: This profile is agnostic about the format of the version argument in | ||
> `id`-based version identifiers. For example, one server may use integers as | ||
> revision IDs, another may use UUIDs and yet another may use content-based | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This note could go away by defining it as an opaque string, like I suggested above. |
||
> hashes. | ||
|
||
## Relative Version Negotiator | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
This profile establishes the `rel` version negotiator. A `rel`-based version | ||
identifier is composed of two or more segments. The first segment **MUST** be | ||
`rel` and the following version arguments describe a resource version that is | ||
relative to the version history. | ||
|
||
The resource version returned for any given version argument in a `rel`-based | ||
version identifier **MAY** change over time. | ||
|
||
The `rel` version negotiator has the following valid version argument strings: | ||
|
||
- `latest-version`: requests the latest default revision of a resource. | ||
- `working-copy`: requests revision of a resource to which changes can be | ||
made. | ||
|
||
If any of the following version arguments is received in a `rel`-based version | ||
gabesullice marked this conversation as resolved.
Show resolved
Hide resolved
|
||
identifier, the server **MUST** respond with a `501 Not Implemented`: | ||
|
||
- `predecessor-version` | ||
- `successor-version` | ||
- `prior-working-copy` | ||
- `subsequent-working-copy` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
revisions → versions :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not in this instance, remember: "not all revisions are versions, but all versions are revisions"