Re: PATCH Use Case and Implemented Proposal

On Sep 7, 2013, at 22:39, Sandro Hawke <sandro@w3.org> wrote:

> Thanks for something so concrete, Dave.   For myself, much of the challenge here is that I've not had time to implement, so it remains too abstract.    Some questions and thoughts, inline....
> 
> On 09/07/2013 09:09 PM, David Wood wrote:
>> Hi all,
>> 
>> The need for a PATCH format for LDP was brought up again in last week's meeting with TimBL [1].  To summarize briefly, Tim made the point that LDP has no generic way to update data without a PATCH format and Arnaud said that the WG wanted one but hadn't yet been able to define it.  Arnaud called for a halt on PATCH formats in May [2]
>> 
>> The two main approaches would seem to be Andy's proposal [3] which uses basic triple patterns to define what to add or remove from a store and Sandro's TurtlePatch [4].
>> 
> 
> I also did a Trig-based patch format, DataPatch: http://www.w3.org/People/Sandro/datapatch but like TurtlePatch I haven't actually been pushing it.    But it was going the direction the WG said it wanted to go, using TriG.
> 
>> This message suggests a third approach based on a strictly defined subset of SPARQL Update
> 
> Isn't that exactly what TurtlePatch was? 


Yep, sloppy phrasing.  Sorry.


>     True, your subset is somewhat..
> 
>> .  Our approach is already implemented in the (Apache 2 licensed) Callimachus Project [5] and documented later in this message.  Henry has already mentioned that a subset of SPARQL Update could work [6] for the WG's purposes.
>> 
>> A strict subset of SPARQL Update is used in the Callimachus implementation to support the following constructs in a PATCH request. However, each clause can only contain zero or more basic graph patterns and only the default graph can be used.
>>      * DELETE DATA
>>      * INSERT DATA
>>      * DELETE WHERE
>>      * INSERT WHERE
>>      * DELETE INSERT WHERE
>> 
>> Callimachus further restricts the SPARQL Update spec such that all nodes are connected and all URIs, in the subject position, before a '#' (if present), are the same.
>> 
> 
> What's the reasoning behind this?   I've always assumed that a basic requirement of Patch was that it be able to patch any RDF graph to any other RDF graph (given enough computing resources).    Is there some other requirement that necessitates this restriction?


It seems obvious to me that in the context of a REST API you don't want to be able to allow the addressing of one resource to be be able to be used to update another.  So, security and the making of intention concrete are good reasons.  Another is that this approach is easier to validate against the target URI.

Regards,
Dave
--
http://about.me/david_wood


> 
>     -- Sandro
> 
>> Callimachus enforces this by walking the syntax tree of the parsed SPARQL Update request and flags any construct that does fit with the above. Callimachus uses the Sesame query model, which is a bit different than the SPARQRL grammer. The code that walks the SPARQL Update tree and flags constructs that are not explicitly listed is available online at [7].
>> 
>> Then it verifies the request body [8] by checking that all URIs in the subject position (before '#') are the same [9], all nodes are
>> connected [10], all present constructs are permitted[7], and finally it makes sure no blank nodes are left disconnected[11].
>> 
>> To try this out, fire up a Callimachus instance and run the follow curl commands:
>> 
>> ################################
>> # Discover the LDPR of the root resource by looknig for rel="describedby"
>> ################################
>> $ curl -iX OPTIONS http://localhost:8080/
>> 
>> HTTP/1.1 204 No Content
>> Allow: OPTIONS, TRACE, GET, HEAD, POST, PATCH, DELETE, PUT
>> Access-Control-Allow-Methods: OPTIONS, TRACE, GET, HEAD, POST, PATCH, DELETE, PUT
>> Access-Control-Allow-Headers: Accept,Accept-Charset,Accept-Encoding,Accept-Language,Authorization,Cache-Control,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-MD5,Content-Type,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Location,Range,Cookie,Referer,Slug
>> Link: <http://localhost:8080/?discussion>; rel="comments"; type="text/html"
>> Link: <http://localhost:8080/?search>; rel="search"; type="application/opensearchdescription+xml"
>> Link: <http://localhost:8080/?describe>; rel="describedby"; type="text/html application/rdf+xml;q=0.4 text/turtle;q=0.5"; title="RDF Describe"
>> Link: <http://localhost:8080/?realms>; rel="http://callimachusproject.org/rdf/2009/framework#realms"; type="application/atom+xml;q=0.9"
>> Link: <http://localhost:8080/?contents>; rel="contents"; type="application/atom+xml;q=0.9"
>> Link: <http://localhost:8080/?edit>; rel="edit-form"; type="text/html"
>> Link: <http://localhost:8080/?history>; rel="version-history"; type="text/html application/atom+xml;q=0.9"
>> Link: <http://localhost:8080/?view>; rel="alternate"; type="text/html"
>> Link: <http://localhost:8080/?archive>; rel="http://callimachusproject.org/rdf/2009/framework#archive"
>> Link: <http://localhost:8080/?changes>; rel="alternate"; type="text/html"
>> Cache-Control: public
>> Vary: Accept
>> Vary: Origin
>> Vary: Access-Control-Request-Method
>> Content-Version: "/callimachus/changes/2013/09/05/t140ee789cecx1971"
>> ETag: W/"216e0b6d-a038f4fe"
>> Last-Modified: Thu, 05 Sep 2013 15:59:13 GMT
>> Access-Control-Allow-Origin: http://localhost:8080
>> Access-Control-Expose-Headers: Content-Length, Allow, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Link, Cache-Control, Vary, Content-Version, ETag, Last-Modified, Access-Control-Allow-Origin, Content-Type, Content-Encoding, Date, Server
>> Date: Thu, 05 Sep 2013 16:55:48 GMT
>> Server: Callimachus/1.2-beta-10
>> 
>> 
>> ################################
>> # Create a new resource, by POSTing the RDF as sparql-update
>> ################################
>> $ curl -i --digest --user james --data-binary @- -H content-type:application/sparql-update http://localhost:8080/?describe
>> BASE <http://localhost:8080/>
>> PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
>> INSERT DATA {
>>    <sun> a skos:Concept, </callimachus/1.0/types/Concept> ;
>>        skos:prefLabel "Sun" ;
>>        skos:definition "The great luminary" .
>> }
>> 
>> HTTP/1.1 201 Created
>> Location: http://localhost:8080/sun
>> Content-Version: "/callimachus/changes/2013/09/05/t140ee789cecx2216"
>> Derived-From: "/callimachus/changes/2013/09/05/t140ee789cecx2190"
>> ETag: W/"216e64d0-62cbb087"
>> Content-Type: text/uri-list;charset=UTF-8
>> Access-Control-Allow-Origin: http://localhost:8080
>> Access-Control-Expose-Headers: Location, Content-Version, Derived-From, ETag, Content-Type, Access-Control-Allow-Origin, Content-Length, Content-Encoding, Date, Server
>> Date: Thu, 05 Sep 2013 17:02:45 GMT
>> Content-Length: 25
>> Content-Encoding: identity
>> Server: Callimachus/1.2-beta-10
>> 
>> http://localhost:8080/sun
>> 
>> 
>> ################################
>> # Discover the LDPR of the newly created resource
>> ################################
>> $ curl -iX OPTIONS http://localhost:8080/sun
>> 
>> HTTP/1.1 204 No Content
>> Allow: OPTIONS, TRACE, POST, PATCH, GET, HEAD, DELETE
>> Access-Control-Allow-Methods: OPTIONS, TRACE, POST, PATCH, GET, HEAD, DELETE
>> Access-Control-Allow-Headers: Accept,Accept-Charset,Accept-Encoding,Accept-Language,Authorization,Cache-Control,Content-Encoding,Content-Language,Content-Length,Content-Location,Content-MD5,Content-Type,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Location,Range
>> Link: <http://localhost:8080/sun?history>; rel="version-history"; type="text/html application/atom+xml;q=0.9"
>> Link: <http://localhost:8080/sun?discussion>; rel="comments"; type="text/html"
>> Link: <http://localhost:8080/sun?describe>; rel="describedby"; type="text/html application/rdf+xml;q=0.4 text/turtle;q=0.5"; title="RDF Describe"
>> Link: <http://localhost:8080/sun?edit>; rel="edit-form"; type="text/html"
>> Link: <http://localhost:8080/sun?view>; rel="alternate"; type="text/html"
>> Cache-Control: public
>> Vary: Accept
>> Vary: Origin
>> Vary: Access-Control-Request-Method
>> Content-Version: "/callimachus/changes/2013/09/05/t140ee789cecx2216"
>> ETag: W/"216e64d0"
>> Last-Modified: Thu, 05 Sep 2013 17:02:45 GMT
>> Access-Control-Allow-Origin: http://localhost:8080
>> Access-Control-Expose-Headers: Content-Length, Allow, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Link, Cache-Control, Vary, Content-Version, ETag, Last-Modified, Access-Control-Allow-Origin, Content-Type, Content-Encoding, Date, Server
>> Date: Thu, 05 Sep 2013 17:03:44 GMT
>> Server: Callimachus/1.2-beta-10
>> 
>> 
>> ################################
>> # Now update the resource using a subset of sparql-update
>> ################################
>> $ curl --digest --user james -X PATCH --data-binary @- -H content-type:application/sparql-update http://localhost:8080/sun?describe
>> PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
>> DELETE DATA {
>>    </sun> skos:definition "The great luminary" .
>> };
>> INSERT DATA {
>>    </sun> skos:definition "The lamp of day" .
>> };
>> 
>> HTTP/1.1 204 No Content
>> Content-Version: "/callimachus/changes/2013/09/05/t140ee789cecx2245"
>> Derived-From: "/callimachus/changes/2013/09/05/t140ee789cecx2241"
>> ETag: W/"216e652c-469953d3"
>> Access-Control-Allow-Origin: http://localhost:8080
>> Access-Control-Expose-Headers: Content-Length, Content-Version, Derived-From, ETag, Access-Control-Allow-Origin, Content-Type, Content-Encoding, Date, Server
>> Date: Thu, 05 Sep 2013 17:05:48 GMT
>> Server: Callimachus/1.2-beta-10
>> 
>> 
>> With the above, you can try out these other requests below.
>> 
>> The following are some examples of valid PATCH requests:
>> 
>> 
>> PATCH /sun?describe HTTP/1.1
>> Host: localhost:8080
>> Content-Type:application/sparql-update
>> Transfer-Encoding: identity
>> 
>> BASE <http://localhost:8080/>
>> PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
>> DELETE DATA {
>>    </sun> skos:definition "The great luminary" .
>> };
>> INSERT DATA {
>>    </sun> skos:definition "The lamp of day" .
>> };
>> 
>> 
>> PATCH /sun?describe HTTP/1.1
>> Host: localhost:8080
>> Content-Type:application/sparql-update
>> Transfer-Encoding: identity
>> 
>> BASE <http://localhost:8080/>
>> PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
>> INSERT DATA {
>>    </sun> skos:scopeNode "sun is part of our solar system" .
>> }
>> 
>> 
>> PATCH /sun?describe HTTP/1.1
>> Host: localhost:8080
>> Content-Type:application/sparql-update
>> Transfer-Encoding: identity
>> 
>> BASE <http://localhost:8080/>
>> PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
>> DELETE DATA {
>>    </sun> skos:scopeNode "sun is part of our solar system" .
>> };
>> INSERT {
>>    </sun> skos:scopeNode ("sun is part of our " <solarSystem>) .
>> } WHERE {};
>> 
>> 
>> PATCH /sun?describe HTTP/1.1
>> Host: localhost:8080
>> Content-Type:application/sparql-update
>> Transfer-Encoding: identity
>> 
>> BASE <http://localhost:8080/>
>> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
>> PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
>> DELETE WHERE {
>>    </sun> skos:scopeNode ?list0 .
>>    ?list0 rdf:first "sun is part of our "; rdf:rest ?list1 .
>>    ?list1 rdf:first <solarSystem>; rdf:rest rdf:nil .
>> };
>> INSERT {
>>    </sun> skos:scopeNode ("sun is in our " <solarSystem>) .
>> } WHERE {};
>> 
>> 
>> The following requests are INVALID as outlined below.
>> 
>> PATCH /sun?describe HTTP/1.1
>> Host: localhost:8080
>> Content-Type:application/sparql-update
>> Transfer-Encoding: identity
>> 
>> BASE <http://localhost:8080/>
>> PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
>> DELETE {
>>    </sun> skos:definition ?definition .
>> } INSERT {
>>    </sun> skos:definition ?newvalue .
>> } WHERE {
>>    </sun> skos:definition ?definition .
>>    BIND (concat(?definition,"!") AS ?newvalue)
>> };
>> 
>> HTTP/1.1 400 Only basic graph patterns are permitted
>> 
>> 
>> PATCH /sun?describe HTTP/1.1
>> Host: localhost:8080
>> Content-Type:application/sparql-update
>> Transfer-Encoding: identity
>> 
>> BASE <http://localhost:8080/>
>> CREATE GRAPH </sun> 
>> 
>> HTTP/1.1 500 Unsupported type of update statement: Create
>> 
>> 
>> PATCH /sun?describe HTTP/1.1
>> Host: localhost:8080
>> Content-Type:application/sparql-update
>> Transfer-Encoding: identity
>> 
>> BASE <http://localhost:8080/>
>> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
>> PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
>> DELETE WHERE {
>>    </sun> skos:scopeNode ("sun is part of our " <solarSystem>) .
>> };
>> INSERT {
>>    </sun> skos:scopeNode ("sun is in our " <solarSystem>) .
>> } WHERE {};
>> 
>> HTTP/1.1 500 DELETE WHERE may not contain blank nodes
>> 
>> 
>> Using a sparql-update grammer parser it was fairly easy to limited the
>> tokens to a subset that can be validated easily, yet useful to the
>> client.
>> 
>> 
>> Regards,
>> Dave, with massive work by James Leigh
>> --
>> http://about.me/david_wood
>> 
>> 
>> [1] http://www.w3.org/2013/meeting/ldp/2013-09-03
>> [2] http://lists.w3.org/Archives/Public/public-ldp-wg/2013May/0233.html
>> [3] http://afs.github.io/rdf-patch/
>> [4] http://www.w3.org/2001/sw/wiki/TurtlePatch
>> [5] http://callimachusproject.org
>> [6] http://lists.w3.org/Archives/Public/public-ldp-wg/2013May/0239.html
>> [7] https://code.google.com/p/callimachus/source/browse/tags/1.1.2/src/org/callimachusproject/form/helpers/TripleAnalyzer.java#220
>> [8] https://code.google.com/p/callimachus/source/browse/tags/1.1.2/src/org/callimachusproject/form/helpers/EntityUpdater.java#105           
>> [9] https://code.google.com/p/callimachus/source/browse/tags/1.1.2/src/org/callimachusproject/form/helpers/TripleVerifier.java#176
>> [10] https://code.google.com/p/callimachus/source/browse/tags/1.1.2/src/org/callimachusproject/form/helpers/TripleVerifier.java#289
>> [11] https://code.google.com/p/callimachus/source/browse/tags/1.1.2/src/org/callimachusproject/form/helpers/EntityUpdater.java#98
>> 
> 

Received on Sunday, 8 September 2013 15:38:01 UTC