Re: ETags, If-Match and database versions

This is almost exactly the scenario I'm talking about though. The only
major difference is that I'm not storing the document as-is but instead
storing it as data fields in a database.

So, for a worked example, say I've got a database record of:

   - id: abc123
   - version: 1
   - title: Some Article Title
   - content: Some Article Content

I can then have a call to "GET /articles/abc123" that returns this as JSON
- for example:
{
    "title": "Some Article Title",
    "content": "Some Article Content"
}

And I can also have a call to "PUT /articles/abc123" that updates this.

As best I can tell, that's pretty much exactly the same as the "Editing the
Web" spec is describing. In fact, from the point of view of the client,
it's indistinguishable from it...

The only major difference - which is only discernable within the backend
and not outside of it - is the fact that I'm not storing the JSON directly.
Instead, I'm generating it from the stored data. However, that in turn
means that - by my understanding of the specs - the "version" field from
the database shouldn't directly be a *strong* etag. I'm saying this
because, theoretically, a minor update to the server could change the exact
way the JSON is generated in a way that's semantically the same but isn't
the same string of bytes - e.g. it might stop pretty-printing it, or it
might change the order the fields are returned. None of those changes have
any impact on the meaning of the JSON returned, but they do have an impact
on the exact bytes returned for this representation, and thus are
"observable in the content of a 200 (OK) response to GET".

As such, it seems that it's intended that either a strong etag is generated
from the generated bytes returned for the response - which is hard to do,
especially when your backend architecture has a strict separation between
the presentation layer that generates the JSON and the application layer
that does the version checking - or else a weak etag can be returned based
on the "version" field in the database - which is much easier to do, makes
much more sense, but then breaks the rules around If-Match...

Or, is the "Editing the Web" spec simply not designed for this kind of
scenario? In which case, is there an alternative that is intended for it?
Because it seems a real shame to have a spec that so nearly, but not quite,
works perfectly for this case...

Cheers

On Fri, 27 Dec 2024 at 22:40, Mark Nottingham <mnot@mnot.net> wrote:

> Ah, yes - sorry, that is the case. If-Match is really for cases like this:
>   https://www.w3.org/1999/04/Editing/
>
> Cheers,
>
>
> > On 28 Dec 2024, at 9:36 am, Graham Cox <graham@grahamcox.co.uk> wrote:
> >
> > There is, and it defines the "strong comparison function" as:
> > > Strong comparison:two entity tags are equivalent> if both are not weak
> and their opaque-tags match> character-by-character.
> > It's also got a table to make it clear that the strong comparison
> function only works if both sides of the comparison are strong etags...
> > I.e., by that wording you're not able to use the strong comparison
> function - as required by the If-Match header - on weak etags.
> > Or is there somewhere else that overrides this for this scenario?
> > Cheers
> >
> >
> > On Fri, 27 Dec 2024, 22:26 Mark Nottingham, <mnot@mnot.net> wrote:
> > There's a specific definition of the comparison function here:
> >   https://httpwg.org/specs/rfc9110.html#entity.tag.comparison
> >
> > To summarise, you can use weak ETags, but in this case you need to
> compare them as if they were strong.
> >
> > Cheers,
> >
> >
> > > On 28 Dec 2024, at 2:14 am, Graham Cox <graham@grahamcox.co.uk> wrote:
> > >
> > > Hi there,
> > >
> > > I've been implementing optimistic locking in my REST API, and have run
> into some awkwardness with the way ETags work per RFC-9110. And I'm
> wondering if I'm missing something obvious...
> > >
> > > Firstly, we've got the entire concept of strong and weak ETags. In
> particular, RFC-9110 states:
> > > > A "strong validator" is representation
> > > > metadata that changes value whenever a
> > > > change occurs to the representation data that
> > > > would be observable in the content of a 200
> > > > (OK) response to GET.
> > >
> > > > In contrast, a "weak validator" is
> > > > representation metadata that might not
> > > > change for every change to the
> > > > representation data. This weakness might be
> > > > due to limitations in how the value is
> > > > calculated (e.g., clock resolution), an inability
> > > > to ensure uniqueness for all possible
> > > > representations of the resource, or a desire of
> > > > the resource owner to group representations
> > > > by some self-determined set of equivalency
> > > > rather than unique sequences of data.
> > > https://datatracker.ietf.org/doc/html/rfc9110#section-8.8.1
> > >
> > > So, I read that to mean that if you're using a strong etag then it
> should be generated based on the bytes-on-the-wire. Or, to put another way,
> if you're using the database stored version of the data then it should be a
> weak etag instead. In particular since a change in the formatting of the
> data - pretty printing, field order, etc - might have no impact on the
> meaning of the data but does change the bytes sent.
> > >
> > > Which is all pretty reasonable. And is easy to handle, which is nice.
> > >
> > > However, if we then get to the If-Match header then we see this:
> > > > An origin server MUST use the strong
> > > > comparison function when comparing entity
> > > > tags for If-Match
> > >
> > > So, if we're using weak ETags then we "can't" use If-Match.
> > >
> > > Which, all combined, would seem to mean that we can't use If-Match for
> optimistic locking based on database stored versions.
> > >
> > > Is this right? Or am I missing something?
> > >
> > > Cheers
> >
> > --
> > Mark Nottingham   https://www.mnot.net/
> >
>
> --
> Mark Nottingham   https://www.mnot.net/
>
>

Received on Friday, 27 December 2024 23:18:39 UTC