W3C home > Mailing lists > Public > public-ldp-wg@w3.org > October 2012

Re: ldp-ISSUE-20 (POSTed resources): Identifying and naming POSTed resources [Use Cases and Requirements]

From: Andy Seaborne <andy.seaborne@epimorphics.com>
Date: Tue, 09 Oct 2012 11:35:34 +0100
Message-ID: <5073FDF6.6090900@epimorphics.com>
To: public-ldp-wg@w3.org
It's a useful idea and one we may have to adopt.

Its hard to see how the client can send such a request though if it is 
not manipulating purely syntax documents.  RDF is based on absolute IRIs 
so sending an RDF graph can't be simply a case of serializing some legal 
RDF if there are special rules.  That may make it hard to work with 
available RDF toolkits.

The rules for Base URI determination are in RFC 3986 section 5.1
http://tools.ietf.org/html/rfc3986#section-5.1

5.1.3 seems to apply although the whole section is more GET oriented.
My test case is what does "<>" mean if the container sends it back - 
surely its the same as if "<>" is sent to the container?

One light is that the container is within its rights to modify the RDF 
sent to store something else at the new BPR location (SteveB's bNode 
idea for example).

Redirection (conceptual or real) may provide an opening:
POST -> 303 to actual BPR location.

	Andy

On 09/10/12 10:35, Henry Story wrote:
>
> On 8 Oct 2012, at 19:35, Henry Story <henry.story@bblfish.net
> <mailto:henry.story@bblfish.net>> wrote:
>
>>
>> On 8 Oct 2012, at 11:52, Linked Data Platform (LDP) Working Group
>> Issue Tracker <sysbot+tracker@w3.org <mailto:sysbot+tracker@w3.org>>
>> wrote:
>>
>>> ldp-ISSUE-20 (POSTed resources): Identifying and naming POSTed
>>> resources [Use Cases and Requirements]
>>>
>>> http://www.w3.org/2012/ldp/track/issues/20
>>>
>>> Raised by: Steve Battle
>>> On product: Use Cases and Requirements
>>>
>>> Regarding use-case :
>>> <http://www.w3.org/2012/ldp/wiki/Use_Cases_And_Requirements#UC-BPC2:_Create_resource_within_a_container>
>>>
>>> User-story
>>> <http://www.w3.org/2012/ldp/wiki/Use_Cases_And_Requirements#Hosting_POSTed_Resources>
>>> raises questions about POSTed resources.
>>>
>>> * How is the inserted resource identified?
>>> The use-case scenario assumes that the inserted resource is
>>> identified by including its relation via the membership predicate, to
>>> the membership subject.
>>> e.g.
>>>
>>> <> rdfs:member [
>>>     a helios_bt:BugtrackerIssue;
>>>     dc:identifier"58365";
>>>     dc:type"bug";
>>>     helios_bt:isInBugtracker eg:bugtracker
>>>  ]
>>
>>
>>>
>>> * How does the created resource relate to the RDF description?
>>> See user-story
>>> <http://www.w3.org/2012/ldp/wiki/Use_Cases_And_Requirements#Hosting
>>> POSTed Resources>.
>>>
>>> The example above assumes that the object of the insert is an
>>> anonymous (existentially quantified) resource that can be skolemized
>>> to produce a URI that can be returned in the Location header.
>>>
>>> e.g. The response the the POST
>>>
>>> HTTP/1.1 201 Created
>>> Location: http://example.com/bugtracker/a0001
>>> ETag: W/"1234567890"
>>
>>
>> I think the answer to this problem is simple and requires some text in
>> section 4.3
>> http://www.w3.org/2012/ldp/hg/ldbp.html#http-post
>>
>> to the effect that: one should POST an RDF document to a collection
>> with relative
>> URIs such that the relatives URIs in the document will be resolve
>> relative to the
>> URI created by the server for that resource.
>>
>> So if you post
>>
>> ------------------------
>> <> a foaf:PersonalProfileDocument;
>>   foaf:primaryTopic <#me> .
>>
>> <#me> a foaf:Person;
>>     foaf:name "Henry" .
>> ------------------------
>>
>> to a collection
>>
>> http://profile.example/2012/
>>
>> then the server will create a resource http://profile.example/2012/93
>> against which the above document with relative URLs will be resolved
>> so that one ends up with a document which is isomorphic to
>>
>> ------------------------
>> <http://profile.example/2012/93> a foaf:PersonalProfileDocument;
>>   foaf:primaryTopic <#me> .
>>
>> <http://profile.example/2012/93#me> a foaf:Person;
>>     foaf:name "Henry" .
>> ------------------------
>
> Btw, I had implemented this a while ago here, so it does work, and
> pretty nicely too:
>
> https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l150
>
> 150
> <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l150>case
> POST(_) & RequestContentType(ct) if representation == DirectoryRepr =>
>
>     151  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l151>                val createType = Representation.fromAcceptedContentTypes(List(ct))
>
>     152  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l152>                r.create(createType) failMap { t => NotFound ~> ResponseString(t.getStackTraceString)} flatMap { rNew =>
>
>     153  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l153>                  Post.parse(Body.stream(req), rNew.name, ct) match {
>
>     154  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l154>                    case PostRDF(model) => {
>
>     155  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l155>                      logger.info("RDF content:\n" + model.toString())
>
>     156  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l156>                      for {
>
>     157  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l157>                        _ <- rNew.save(model) failMap {
>
>     158  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l158>                          t => InternalServerError ~> ResponseString(t.getStackTraceString)
>
>     159  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l159>                        }
>
>     160  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l160>                      } yield Created ~> ResponseHeader("Location",Seq(rNew.name.toString))
>
>     161  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l161>                    }
>
>     162  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l162>                    case PostBinary(is) => {
>
>     163  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l163>                      for (_ <- rNew.putStream(is) failMap { t=> InternalServerError ~> ResponseString(t.getStackTraceString)})
>
>     164  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l164>                      yield Created ~> ResponseHeader("Location",Seq(rNew.name.toString))
>
>     165  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l165>                    }
>
>     166  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l166>                    case _ => {
>
>     167  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l167>                      logger.info("Couldn't parse the request")
>
>     168  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l168>                      (BadRequest ~> ResponseString("You MUST provide valid content for given Content-Type: " + ct)).success
>
>     169  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l169>                    }
>
>     170  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l170>                  }
>
>     171  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l171>                }
>
>     172  <https://dvcs.w3.org/hg/read-write-web/file/258d2757ef3d/src/main/scala/ReadWriteWeb.scala#l172>
>
>
> rNew is the new resource created in the collection.
> Post.parse parses the inputstream and de-relativises all URLs to the new
> url.
> ( Of course one would get the same effect if one just placed the
> unparsed document at that location with its relative urls )
>
> so the advantage of this is that it does not even require the rdf to be
> parsed to work correctly.
>
> Henry
>
>>
>>
>>
>>
>>>
>>>
>>> * Should POST support a user supplied local-name 'hint'; e.g. based
>>> on the supplied rdfs:label, to support more human-readable URIs?
>>
>> yes, Atom has something on this I think
>> http://tools.ietf.org/html/rfc5023#section-9.7
>>
>> If it is good enough one should probably use that as they spent
>> enormous amounts of time
>> discussing that.
>>
>>> Alternatively, an owl:sameAs could be used in the above to provide a
>>> user-friendly name.
>>>
>>>
>>>
>>
>> Social Web Architect
>> http://bblfish.net/
>>
>
> Social Web Architect
> http://bblfish.net/
>
Received on Tuesday, 9 October 2012 10:36:08 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 16:17:32 UTC