Skip to content

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

Open
wants to merge 27 commits into
base: gh-pages
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
df9838a
Create resource-versioning index.md.
gabesullice Dec 12, 2018
e815ccd
Add a "Resource Versioning" profile category
gabesullice Dec 13, 2018
c302a8c
Add all editors to this profile
gabesullice Dec 13, 2018
84d4840
Fix spacing
gabesullice Dec 13, 2018
ea9c13c
Use editor format from #1349
gabesullice Dec 20, 2018
9d9e263
move 501 to relative version section
gabesullice Dec 20, 2018
9368cbc
disambiguate bad version negotiator vs. argument errors
gabesullice Dec 20, 2018
d3c1d13
add trailing slash to error type URIs
gabesullice Dec 20, 2018
cac4baf
add linking and version history section
gabesullice Dec 20, 2018
56bc05e
fixup link and version history commit
gabesullice Dec 20, 2018
75659ce
add to and fix link example table
gabesullice Dec 20, 2018
2d5346e
typos and clarification
gabesullice Dec 20, 2018
c351d9c
change the query parameter from snake-case to camel-case
gabesullice Dec 20, 2018
3e4b67e
clarify that a one-segment version identifier is valid
gabesullice Dec 21, 2018
515aba9
invert definition of a version
gabesullice Dec 21, 2018
0feddd6
clarify the example narrative of a version history
gabesullice Dec 21, 2018
b0a1e3d
relax `type` link requirement
gabesullice Dec 21, 2018
f0d73db
clarify interoperability and optionality of version negotiators
gabesullice Dec 21, 2018
a4329d5
the first or only segment of a version identifier must be interpreted…
gabesullice Dec 21, 2018
7a352dc
restrict usage of the rel negotiator in resource objects' `self` links
gabesullice Dec 21, 2018
9129eb2
reduce redundancy
gabesullice Dec 21, 2018
ba9bf0b
use the `source` error object member in error details
gabesullice Dec 21, 2018
6bc95be
disallow custom rel-based version arguments
gabesullice Dec 21, 2018
1a1395d
reorder two lines
gabesullice Dec 21, 2018
e4adbd7
fix some ascii art
gabesullice Dec 21, 2018
5c5b0f4
fix italicization
gabesullice Dec 21, 2018
c82ecbe
update mateu's contact info
gabesullice Dec 21, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add linking and version history section
  • Loading branch information
gabesullice committed Dec 20, 2018
commit cac4baf090f6a281e318efeeb25f63cf64f79380
90 changes: 90 additions & 0 deletions _profiles/drupal/resource-versioning/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,96 @@ object that includes a `type` link to
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`.

# Links

When a server processes a request with a `resource_version` query parameter and
a `self` link is provided for a top-level links object, the link's `href`
**MUST** include the `resource_version` query parameter with the same version
identifier that was requested.

When a server processes a request with a `resource_version` query parameter and
all resource object `self` links **SHOULD** contain a `resource_version` query
parameter which identifies the specific revision represented by that resource
object.

For example, in the following response document the `self` links are not the
same:

```json
{
"data": {
"type": "article",
"id": 1,
"links": {
"self": "/article/1?resource_version=id:42"
}
},
"links": {
"self": "/article/1?resource_version=rel:latest-version"
}
}
```

A server **MAY** provide a `version-history` link in a resource object's links
object. This link must reference a collection resource providing all revisions
of the context resource object.

A server **MAY** provide the following resource object links so that a client may
navigate a resource object's version history:

- `latest-version`: links to the latest version of the context resource
object.
- `working-copy`: links to the working copy of the context resource object.
- `predecessor-version`: links to the version which immediately preceded the
context resource object.
- `successor-version`: links to the version which immediately succeeded the
context resource object.
- `prior-working-copy`: links to the working copy which immediately preceded
the context resource object.
- `subsequent-working-copy`: links to the working copy which immediately
preceded the context resource object.

A server **MAY** provide an array of any of these links to support branching.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ethanresnick, this is in conflict with the base spec. Not sure what to do or how to accommodate this in any other way. Perhaps you have some ideas?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabesullice I'd be happy to just define these links in the base spec as a temporary workaround. Note also that the base spec's current approach is that, if an array of links is allowed, an array should be required (like we did for profile) to not further proliferate the number of links cases that clients have to handle.

So, the base spec language would go under the resource links section, and could say something like:

If present, this object MAY also contain an array of links as the value for any of the following keys: latest-version, working-copy, predecessor-version, successor-version, [etc]. Links at any of these keys point to resources that are related to the resource object according to the IANA link relation corresponding to their key name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'd be great :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bump.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ethanresnick Rather than calling out those 4 specific link relations, perhaps it'd be better to generalize that to something like:

Links with a key that matches a registered link relation type which allows multiple values are allowed to have a value that is not a link, but an array of links.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I agree that calling out specific link relations "smells" a bit, I would not like to see the concept of links object keys as link relations furthered in the spec. Links can have more than one link relation and this pattern makes that more challenging to fix in later iterations of the spec.


For example, in the following version history:

```
_c_
/ \
/__b__d__ __f__ __h
/ \ / \ /
a e g
```

`g` is the latest version. Both `a` and `e` were previously the latest version.
No other revisions were ever the latest version. In this example, the following
links could be provided:

| revision | `latest-version` | `working-copy` | `predecessor-version` | `successor-version` | `prior-working-copy` | `subsequent-working-copy` |
| `a` | `g` | `h` | no link | `e` | no link | `b` |
| `b` | `g` | `h` | `a` | `e` | `a` | `c` |
| `c` | `g` | `h` | `a` | `e` | `b` | `d` |
| `d` | `g` | `h` | `a` | `e` | `c` | `e` |
| `e` | `g` | `h` | `a` | `g` | `d` | `f` |
| `f` | `g` | `h` | `e` | `g` | `e` | `g` |
| `g` | no link | `h` | `e` | no link | `f` | `h` |
| `h` | `g` | no link | `e` | no link | `g` | no link |

> Note: In this example, `f` has both a `predecessor-version` and
> `prior-working-copy` link to `e` because `e` was a version but it also was the
> revision to which changes could be applied before `f` was created.

# Version History

A server **MAY** provide a "version history" endpoint. The primary data
of a response document from a version history endpoing must be a collection of
resource objects.

Unless an `id` contains version information, the `type` and `id` members of each
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Spec compliance] Having multiple resource objects in data with the same type/id is sort of a spec violation. I say "sort of" because the spec technically says only that:

A compound document MUST NOT include more than one resource object for each type and id pair.

So, if this version history response isn't a compound document, you're technically in the clear. But the intent has always been that this restriction should apply to all responses. (I can't find the link for that now, but it's come up in conversations with @dgeb over the years.)

Note: I've also proposed removing the restriction altogether.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not intended to be a compound document.

I don't think this profile can impose a requirement that ids contain version information. I think most systems store revision IDs separately from the entity ID. In our case, we use UUIDs for id and revision IDs are auto-incrementing integers. We'd have to make some wonky concatenation of these to put revision IDs into our resource object IDs and I don't think this profile should define how to do that.

I've been considering adding a recommendation that implementations add information to resource object's meta object that matches their most-specific version negotiator. For example, in our case (since we implement the id negotiator) we'd have:

{
  "type": "article",
  "id": "some-long-uuid",
  "meta": {
    "resourceVersionId": 42
  },
  "links": {
    "self": "/articles/some-long-uuid?resourceVersion=id:42"
  }
}

The rule would be something like:

It is RECOMMENDED that resource object's meta object contains a member whose name is resourceVersion appended by the upper-camel-cased name of the version negotiator used in the resource object's self link. The value of this member should be the the version identifier used in the resource object's self link, excluding its first segment, and it MUST NOT begin with a colon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just read the #824 PR. I like the idea of a revision key. This profile could adopt revision as a meta object member and require that it must be equal to the complete version identifier in a resource object's self link (or a valid one if a self link is not provided).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@e0ipso @wimleers thoughts? ^

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also like a revision key (or version). This would also address @ethanresnick's "sort of" spec violation concern: if present, then it would be a higher specificity resource identifier (or perhaps even an intra resource identifier?): just like [type, id] uniquely identify a resource, [type, id, version] uniquely identifies a version of that resource.

Taking this further, there are multiple potential axes along which a variant of a resource can exist: version (or revision) is one, lang (or translation) is another. I think those are the two clearest, strongest use cases. It's possible to think of others though, such as localization.

I'd say versioning and translations are the two most common needs. I think we should keep both in mind if we're going to go this direction.

But for the sake for consistency and optionality (to ensure backwards compatibility & evolvability), I think we should consider not adding a version key, but a variant key. Under variant, this profile could then reserve the version key. A translation profile could reserve the translation key. This also opens the door for multiple versioning profiles if there is the need.

After having written this, I continued reading #824, to make sure I didn't miss anything. I think my variant proposal would actually address the "identity" concerns that @ethanresnick raised in
#824 (comment)? :)

Copy link
Contributor Author

@gabesullice gabesullice Jan 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crazy thought... maybe we could we extract a variant profile out of this profile? Re-minting resource_version as resource_variant. The "negotiation mechanism" would become the variant negotiation mechanism. Then you could have something like ?resource_variant=lang:en-US or resource_variant=revision:id:42 or ?resource_variant=revision:rel:working-copy.

In fact, if this variation scheme were part of the base spec, then revisions, translations, etc could just enhance that mechanism for its needs.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wimleers noted very important thing. It's not enough to add version of the resource because each resource could have many translations and each translation could have it's own versions.

Copy link

@antonkomarev antonkomarev Feb 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Word locale could be considered for translation purposes instead of lang abbreviation.

resource object in the collection **MUST** be the same.

If provided, resource objects' `self` links **MUST NOT** be the same.

# Version Negotiators
Copy link
Member

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I've done is applied the implementation-specific query parameter name constraints as a version negotiator constraint and added a mechanism for adding new negotiators to the profile.

Changes here: f0d73db

Elsewhere, @e0ipso suggest that we use URIs but I think this is sufficient. @e0ipso, WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc: @wimleers cause it's his inbox that I suggested too 😛

Copy link

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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:

Note: Don't be shy! New version negotiators are more than welcome, the editors want to see this profile proliferate and that means accepting versioning strategies like yours!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@e0ipso, would that work?


## ID-Based Version Negotiator
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy