- From: David Wood <david@3roundstones.com>
- Date: Sat, 7 Sep 2013 21:09:31 -0400
- To: public-ldp-patch@w3.org
- Message-Id: <B78947A9-EF62-4DD5-B651-88A038A84316@3roundstones.com>
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]. This message suggests a third approach based on a strictly defined subset of SPARQL Update. 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. 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
Attachments
- application/pkcs7-signature attachment: smime.p7s
Received on Sunday, 8 September 2013 01:09:55 UTC