braid-spec
braid-spec copied to clipboard
Maybe add Accept-Range-Patch header
For server to announce that it accepts range patches, more precisely, that which range units it accepts for non-GET requests.
- How do we communicate which non-GET requests accept range units?
- Should we have this header, or something else which tells that resource is Braid-enabled more in general? Or both?
@mitar Can you please provide example use-cases for this? Or shall we close it?
So the idea is that you should know that server supports different and which range units.
I understand the idea, but I would really like to see some use-cases for it so that we can prioritize. (edited)
I mean, that comes from our work on the spec. We are extending range header to non-GET requests. it is important for the server to communicate that it supports that. So this is motivated by the correctness of the protocol, not from an use case.
@mitar Are you aware of the Range-Request-Allow-Methods and Range-Request-Allow-Units headers that are currently in the range-patch spec? These seem to do the same thing.
Link: https://github.com/braid-org/braid-spec/blob/master/draft-toomim-httpbis-range-patch-01.txt#L500
It looks like @brynbellomy contributed these headers to the draft on the same day as this issue was created.
I'm also noticing that most of what we want here could be provided by the existing Accept-Patch header defined in rfc5789 Section 3.1. This header seems to have two advantages over the options we've specified so far:
- it works for arbitrary patch formats; not just Range-Patch
- and it is already a standard in HTTP
However, I see two things currently lacking with Accept-Patch:
- In order to say that a server accepts a range-patch, we need a media type for range patches, so that we can say something like
Accept-Patch: application/range-patch; unit=json. Note that the media-type would need to specify the range unit as well for it to work with Accept-Patch. Accept-Patchonly specifies which patch types are accepted by a server; not which HTTP methods are allowed (as inRange-Request-Allow-Methods)
Yet, when I zoom out, I don't see any actual use-case for (2), where a server needs to specify that it will accept a patch for some methods but not for others. The only possible methods that could get listed here are PUT, PATCH, and POST. If a server can support patches at one of these, it can probably support patches at the others, and if not, it seems like that'd be a part of the server's API documentation and not something that needs to be auto-discovered in an OPTIONS request. Can someone please correct me if I'm wrong about this?
I also noticed that the existing media-type we've specified for range patches doesn't meet the needs of (1), because they don't include the range units. As far as I can see, we have specified these definitions of a range patch:
Thus, it seems that instead of these new headers, we could just define a media-type for a range-patch that can be parameterized with its range-unit. Then the existing Accept-Patch header would suffice for advertising support of any patch, including range patches. This would give us one less thing to take through the standardization process.
I'd love to get a reality check here, though. @mitar and @brynbellomy does this reasoning make sense to you?
Hmm, I've realized that this issue also connects with @brynbellomy's way of requesting that a server return patches vs. full state snapshots. Bryn currently adds this information to the Subscribe: header (as described here):
Subscribe: statesSubscribe: txsSubscribe: states,txs
In this model, the client specifies states to request full state snapshots, and txs to request patches.
However, if the server can specify which types of patches it is capable of accepting with the Accept-Patch header, then it stands to reason that a client might also pass an Accept-Patch header to specify which types of patches it's capable of receiving.
This header hasn't been necessary in HTTP until Braid, because patches have only been sent from client-to-server, never from server-to-client. But now that we're sending patches in the opposite direction, it would make sense to just make the protocol symmetric, and use the same header for a client to advertise its capabilities that a server uses to advertise its own capabilities.
Thus, after all these discoveries, I'm proposing that we make the following changes to the spec:
- Specify that servers use the
Accept-Patchheader to specify which patch types it accepts - Specify that clients use the
Accept-Patchheader to specify which patch types they want in response - Add a media-type for range patches that is parameterized by range unit, e.g.
application/range-patch; unit=json
This re-uses existing HTTP headers, and gives us a (perhaps) useful new content-type for range patches. It doesn't allow a server to specify which methods support which patch types, but that doesn't seem necessary. Please correct me if I'm missing something.
Ooo, here's another discovery: HTTP already has an Accept-Ranges header that can specify the range units a server accepts. Example:
Accept-Ranges: json
So if we create a range-patch media type, then a server could advertise that it supports json range patches with:
Accept-Patch: multipart/range-patch
Accept-Ranges: json
I do feel it's a little odd to invent a media-type for a range patch. However, there's already some precedent in existing HTTP range requests to return multipart byte ranges with the multipart/byteranges media type: https://tools.ietf.org/html/rfc7233#appendix-A
On the other hand, it seems that multipart formats are required to have byte-boundary separators:
In the case of multipart entities, in which one or more different
sets of data are combined in a single body, a "multipart" media type
field must appear in the entity's header. The body must then contain
one or more body parts, each preceded by a boundary delimiter line,
and the last one followed by a closing boundary delimiter line.
https://tools.ietf.org/html/rfc2046#section-5.1
And this rfc2046 stuff is explicitly required of all multipart media-types in rfc6838:
Multipart and message are composite types; that is, they provide a
means of encapsulating zero or more objects, each one a separate
media type.
All subtypes of multipart and message MUST conform to the syntax
rules and other requirements specified in [RFC2046] and amended by
Section 3.5 of [RFC6532].
https://tools.ietf.org/html/rfc6838#section-4.2.6
I've found a clear (and perhaps obvious) use-case. This header prevents data loss.
If a server does not understand how to accept a range-patch, then a PUT with a range could obliterate the existing content, instead of patching it.
Thus, clients will want to check whether unknown resources support range patches, with a header like this, before sending them.