Difference between revisions of "Issue-34: Back to Basics"

From Linked Data Platform
Jump to: navigation, search
(UNDER CONSTRUCTION)
m (Creating a member resource: fix link)
Line 313: Line 313:
 
Rather than complicate this further I continue the mainline narrative as if the first was chosen, but keep in mind that the others are allowed (citations to the contrary happily accepted) for any type of collection.
 
Rather than complicate this further I continue the mainline narrative as if the first was chosen, but keep in mind that the others are allowed (citations to the contrary happily accepted) for any type of collection.
  
Note that here I use a <code>Slug: card</code> Header to name the resource as proposed in [http://www.w3.org/2013/ldp/track/issues/43 Issue 43], to get a nice human readable name.
+
Note that here I use a <code>Slug: card</code> Header to name the resource as proposed in [http://www.w3.org/2012/ldp/track/issues/43 Issue 43], to get a nice human readable name.
  
  

Revision as of 19:39, 1 February 2013

1 TOMATO-READY

Insert every disclaimer you can imagine. My own thinking/sandbox, incoherent/rabid, etc.

Its intent is to lay out an alternative, not to compare itself to other proposals. The latter function is for the parent page.

1.1 What are LDP's goals

This is what I think they are:

  1. Define a HTTP interaction model for resources expressible as RDF that is motivated by Use Cases. The interaction model may have some similarities to other existing work, such as base AtomPub's collections. We might need to define a small amount of ontology to meet needs like introspection, but that is a consequence not the goal.
  2. Resources are commonly grouped together, for various purposes. It would be useful if clients had a single interaction model to use with as many of them as possible (ideally, all).
    1. Some groups are views over other groups.
    2. Some groups are read-only.
    3. Some groups implement a factory role used to create new group members.
    4. Some groups are self-contained within a single server, and that can be used to gain implementation efficiencies.
    5. Some groups are implemented by a server using delegation; i.e. when a new member is created, it may be created on a different server than the group-owning server.
    6. Some groups have heterogeneous membership along dimensions like media type.
    7. Some groups fully encompass the lifecycle of their members (popularly known as containment); others are "listings" or "directories" of resources whose lifecycle the group's server does not control (popularly known as aggregation).
  3. Some resources are large enough that servers and/or clients have trouble creating, transferring, or parsing a representation of the entire resource. The usual solution to this is some form of "paging" for the representation. Groups of resources are more likely than average to need this.
  4. Some resources (e.g. groups) have easily separable subsets whose usage is often distinct (e.g. "metadata" about a group) and/or can be small in comparison to other subsets (e.g. group membership). Hence it may be useful to make them separately addressable using HTTP in a way that clients find predictable.
  5. RDF-based resources offer several representation formats. Some popular formats are not yet "standardized", and the standard one(s) have well-known problems, although the former is changing soon. Client code would be simplified if at least one was both widely offered and lacked significant known problems.

There is a tradeoff between simplicity and coverage in constructing the interaction model. When a feature is optional, a debate can arise as to whether to call it a single interaction model with two variants, or two interaction models. If the optionality originates from the base interaction model (in LDP's case, HTTP), and the LDP interaction model only says how an existing option should be interpreted (e.g. factory role), then we still have a single LDP-defined interaction model.

1.1.1 AtomPub Interaction Model

  1. As a recap, base AtomPub defines interaction models only for the following. LDP might have the same scope, might not. But it's a reasonable baseline for comparison, given its wide adoption. Issue-37 will provide some comparisons.
    1. Collections: discover, list, OPTIONALLY create Member Resources, NO mention of deletion
    2. Member resources, with bifurcation for Atom Entry vs other content types: create, edit, delete
  2. AtomPub defines some documents too, for various purposes like discovery, but it defines not interaction model for them.

1.2 Interaction Model

The Interaction Model below captures only the behavioral aspects - the data aspects are rendered using Henry's style formalism in the next section, since data is what RDF is good at describing.


Objects (each potentially a mixture of data and behavioral requirements)

  • Resources
  • Aggregations
  • Containers


Resources (LDP Resources)

  • Behave as described in the LDP spec drafts and submission for ldp:Resource; to summarize the MUSTs informatively:
    • HTTP 1.1
    • Offer RDF representations: Turtle required, others optional, Turtle the default if a request expresses no preferences.
    • HTTP responses include Location header with canonical URL for resource
    • HTTP eTags and conditional requests
    • HTTP GET
    • HTTP HEAD returns Allow header


Aggregations (proposal, is a proper subset of current editor's draft ISSUE-25 resolution for LDP Containers)

  • Adhere to all the behavioral requirements for Resources
  • HTTP GET responses include links to all its 'member' Resources.
  • SHOULD offer separate HTTP GET access to non-member properties.
  • MAY accept HTTP POST requests, following HTTP's semantics.
  • MAY create new Resources in response to POST requests, following HTTP's semantics.
    • Any new Resources it creates are automatically linked to as member Resources.
    • No other relationship between the Aggregation and any Resources it creates exists, either express or implied. Any resources it creates MAY out-live it.
  • MAY accept HTTP DELETE requests, as HTTP allows, and following HTTP's semantics.
  • members MAY also be added through means outside the scope of LDP.


Containers (matches the current editor's draft Jan-21, ISSUE-25 resolution)

  • Adhere to all the behavioral requirements for Aggregations
  • Add an additional constraint on the behavior of HTTP DELETE, i.e. its members never out-live the Container. This is specified somewhat more formally below using Henry's notation:
@prefix ldp: <http://www.w3.org/ns/ldp#>.
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

     If a Container supports the HTTP DELETE method, then its implementation MUST delete all its members.
       More precisely: for a container with URI Uc, and a membership predicate of rdfs:member, 
       let the set of its contents S, be all the results given by the query

           SELECT ?c 
           WHERE {  ?container a ldp:Container; 
                              rdfs:member ?c . }     

      where ?container is bound to Uc. Then deleting the resource named by Uc should delete all 
      the resources named in the set S . 
      Furthermore for any resource ?r in a container ?c, such that 
          ASK { ?c rdfs:member ?r } .
      is true
      If the resource bound to ?r is deleted ( after for example sending to ?r an HTTP DELETE request that is accepted), 
      then ?r must MUST be removed  from the container C, ie:
          ASK { ?c rdfs:member ?r } .
      must be false. 

1.3 Data Model

The ontology below is based on a snapshot of Henry's ISSUE-37#Ontological_Modelling work with the following changes:

  • Copied on 2013-01-22 11:15 EST
  • Focus and simplify by removing dependencies on rdfs:member, i.e. treat the following questions as "to be resolved later"
    • How client "detects" members in a group's representation, i.e. which membership predicate(s) are used
    • Whether or not all types of groups use the same default membership predicate
    • Which membership predicate(s) are used for each type of group.
    • Are membership predicates/subjects introspectable, and if so how.
  • Moved all of the purely behavioral constraints OUT of this section
  • Change sub-classing structure
    • If we stick SOLELY to the DATA level, I'm not convinced LDP needs to distinguish between Aggregation and Container.
    • If we use the assumptions above, I cannot find any DATA differences between the two, only behavioral ones.
    • Once we answer the "how does a client introspect"/"affordances" questions, then perhaps DATA differences emerge.
    • The inheritance choice shown here is I admit influenced by my knowledge that behavioral differences exist. I'm sure there are other alternatives if this is kept purely as a data statement and we decide behavior doesn't/shouldn't enter into it.
@prefix ldp: <http://www.w3.org/ns/ldp#>.
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix vs: <http://www.w3.org/2003/06/sw-vocab-status/ns#> .

ldp:Resource a rdf:Class;
   vs:term_status "unstable";
   rdfs:note "
        An RDF resource that adheres to behavioral constraints defined for LDP Resources.

        rdf:type appears at least once in the triples.
        Links are represented as triples.
    " ;
    vs:term_status "unstable";
    rdfs:subClassOf rdf:Resource .

ldp:Aggregation a rdf:Class;
    rdfs:note "
        An LDP Resource that adheres to behavioral constraints defined for LDP Aggregations.

        Any resources it creates are listed amongst its members. 

        Resolving the deferred questions like introspection/affordances *might* lead to the introduction of data differences.
    " ;
    vs:term_status "unstable";
    rdfs:subClassOf ldp:Resource .

ldp:Container a rdf:Class;
    rdfs:note "
        An LDP Aggregation that adheres to behavioral constraints defined for LDP Containers.

        Separated from Aggregation here only because of behavioral difference leading to the requirement for a unique name.

        Resolving the deferred questions like choice of membership predicate *might* lead to the introduction of data differences.
    ";
    vs:term_status "unstable";
    rdfs:subClassOf ldp:Aggregation .

1.4 Client Interaction Examples

Mirroring Henry's example for starters (copied 2013-01-24 11:20EST). Might need to add Bug Tracker and/or other examples if we discover they cover distinct ground.

1.4.1 Starting Assumptions

Let us make some choices for use in these examples for any deferred questions, i.e.

  • How client "detects" members in a group's representation, i.e. which membership predicate(s) are used
    • Assumption: rdfs:member
  • Whether or not all types of groups use the same default membership predicate
    • Assumption: all these examples use the default, rdfs:member
  • Which membership predicate(s) are used for each type of group.
    • Assumption: all resources use the default, rdfs:member
  • Are membership predicates/subjects introspectable, and if so how.
    • Assumption: not needed, since all these examples use the default, rdfs:member
  • How does a client distinguish aggregations from containers?
    • Assumption: a ldp:Aggregation observes all behavioral constraints for Aggregations
    • Assumption: a ldp:Container does the same for Containers
    • Consequence: a Container object always has both types, if one includes entailed triples.
  • Is the a foaf:PersonalProfileDocument we create as a member resource a ldp:Resource?
    • Assumption: yes - we're not flogging the interaction model for other resources in this page
    • Assumption: /card's content is irrelevant so a minimal one will do fine.
  • Assumption: Using 'collection' here when I mean something that might behave like an aggregation or like a container despite the lack of any formal definition. Just too painful and unhelpfully obfuscating to replace that term with "A or C" everywhere.

1.4.2 Creating a collection

LDP does not specify how any collection is created. It assumes that a client is given a URL to one. We have other open issues that will determine how a client introspects affordances.

Since LDP does not constrain creation, let us start with an empty collection. Since part of the goal here is to show the behavior of Aggregations and Containers side by side, we will show the result of each interaction for both behaviors.

1.4.3 Listing a collection

Since it is empty, a client would expect the following to be true given the provisional assumptions above:

Request

GET /A/ HTTP/1.1
Host: localhost:8888

Response

HTTP/1.1 200 OK

@prefix : <http://www.w3.org/ns/ldp#> .

<> a :Aggregation.


Request

GET /C/ HTTP/1.1
Host: localhost:9999

Response

HTTP/1.1 200 OK

@prefix : <http://www.w3.org/ns/ldp#> .

<> a :Aggregation;
   a :Container.

1.4.4 Updating a collection

HTTP requests like PUT or PATCH against /card are assumed to affect the state of either collection as HTTP/the PATCH RFC defines their semantics. LDP currently adds restrictions on direct modification of membership properties, basically to keep the membership listing under the collection's control.

Do I need to show examples of that here? They might ultimately be useful to spec readers, but I'm not convinced it would advance issue 34's discussion. I have not detected any widespread assertions that aggregations behave differently than containers with regard to modification-but-not-deletion, i.e. HTTP methods other than DELETE.

1.4.5 Deleting an EMPTY collection

Since it is empty, a client would expect the following to be true given the provisional assumptions above:

Request

DELETE /A/ HTTP/1.1
Host: localhost:8888

Response

HTTP/1.1 204 No Content

Request

DELETE /C/ HTTP/1.1
Host: localhost:9999

Response

HTTP/1.1 204 No Content

A client would also expect that all subsequent attempts to list the contents of either collection would result in either 404 Not found or 410 Gone status codes.

In order to explore other behavioral aspects, we need non-empty collections.

1.4.6 Creating a member resource

First, we create a foaf:PersonalProfileDocument in the collection.


Request

POST /A/ HTTP/1.1
Host: localhost:8888
Slug: card

@prefix foaf: <http://xmlns.com/foaf/0.1/> .

<> a foaf:PersonalProfileDocument.

Response

HTTP/1.1 201 Created
Location: card
Content-Length: 0
Location: http://localhost:8888/A/card

Request

POST /C/ HTTP/1.1
Host: localhost:9999
Slug: card

@prefix foaf: <http://xmlns.com/foaf/0.1/> .

<> a foaf:PersonalProfileDocument.

Response

HTTP/1.1 201 Created
Location: card
Content-Length: 0


There are many potential implementation choices for the server; some (non-limiting) examples:

  • The server creates a local resource that it owns, so the resulting url is the one shown above.
  • The server delegates resource creation to a second server, so the resulting url is different, e.g. http://localhost:9001/delegate/card.

Rather than complicate this further I continue the mainline narrative as if the first was chosen, but keep in mind that the others are allowed (citations to the contrary happily accepted) for any type of collection.

Note that here I use a Slug: card Header to name the resource as proposed in Issue 43, to get a nice human readable name.


A client would expect the following to be true:


Request

GET /A/ HTTP/1.1
Host: localhost:8888


Response

HTTP/1.1 200 OK

@prefix : <http://www.w3.org/ns/ldp#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<> a :Aggregation;
     rdfs:member <card> .


Request

GET /C/ HTTP/1.1
Host: localhost:9999


Response

HTTP/1.1 200 OK

@prefix : <http://www.w3.org/ns/ldp#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<> a :Aggregation;
   a :Container;
     rdfs:member <card> .


Note that in both cases the collection now lists /card as a member, as LDP requires.

The collection implementation might choose to maintain other data about the member (e.g. what LDP calls "server managed properties" in places), but that is not required by LDP, and I see no particular reason to expect the behavior to be any different based on the collection's aggregation/container choice, so it is omitted to maintain focus.


For the /card member resource, state aside from the URL should be identical:

Request

GET /A/card HTTP/1.1
Host: localhost:8888


Response

HTTP/1.1 200 OK

@prefix foaf: <http://xmlns.com/foaf/0.1/> .

<> a foaf:PersonalProfileDocument.


Request

GET /C/card HTTP/1.1
Host: localhost:9999


Response

HTTP/1.1 200 OK

@prefix foaf: <http://xmlns.com/foaf/0.1/> .

<> a foaf:PersonalProfileDocument.

1.4.7 Updating a member resource

HTTP requests like PUT or PATCH against /card are assumed to not affect the state of either collection, except as HTTP allows (i.e. as a side effect). LDP is not adding any constraints to HTTP.

Implementations may choose to allow or even depend on such side effects; LDP neither helps nor obstructs them. E.g. a graph store might allow or require a member's triples to also be collection membership triples, and compute membership when the collection is listed. This might allow, for example, a member to be created whose triples assert it membership in multiple collections "atomically". It is up to the server to reject any request it considers incoherent or incompatible with its correct operation.

1.4.8 Deleting a member resource

Assuming that both /card member resources accept HTTP DELETE requests, a client would expect the following to be true given the provisional assumptions above:


Request

DELETE /A/card HTTP/1.1
Host: localhost:8888

Response

HTTP/1.1 204 No Content

Request

DELETE /C/card HTTP/1.1
Host: localhost:9999

Response

HTTP/1.1 204 No Content


A client would also expect that all subsequent attempts to retrieve those member resources would result in either 404 Not found or 410 Gone HTTP status codes.

Since the collections are now empty, a client would expect them to be in the same state they were when first #Listing a collection as required by LDP.

1.4.9 Deleting a NON-EMPTY collection

Let's turn back the clock one step; the member resources have not yet been deleted. Thus the collections look like this:


Request

GET /A/ HTTP/1.1
Host: localhost:8888

Response

HTTP/1.1 200 OK

@prefix : <http://www.w3.org/ns/ldp#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<> a :Aggregation;
     rdfs:member <card> .


Request

GET /C/ HTTP/1.1
Host: localhost:9999

Response

HTTP/1.1 200 OK

@prefix : <http://www.w3.org/ns/ldp#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<> a :Aggregation;
   a :Container;
     rdfs:member <card> .


Since the collections are NOT empty, a client would expect different behavior based on the collection it was interacting with (specifically, a side effect on the member resource's existence) depending upon whether the collection behaved like an aggregation or like a container.

Request

DELETE /A/ HTTP/1.1
Host: localhost:8888

Response

HTTP/1.1 204 No Content


Request

DELETE /C/ HTTP/1.1
Host: localhost:9999

Response

HTTP/1.1 204 No Content

A client would also expect that all subsequent attempts to list the contents of either collection would result in either 404 Not found or 410 Gone status codes.

So far there is no behavioral distinction evident. In order to highlight that, the client now needs to attempt to make HTTP requests using the member resource whose URL it listed previously:


For the /card member resource:

Request

GET /A/card HTTP/1.1
Host: localhost:8888

Response

HTTP/1.1 200 OK

@prefix foaf: <http://xmlns.com/foaf/0.1/> .

<> a foaf:PersonalProfileDocument.


An implementation that only "advertises" itself as an Aggregation could still behave like a container, but that would likely surprise clients so I treat it as an edge case.


Request

GET /C/card HTTP/1.1
Host: localhost:9999

Response

HTTP/1.1 404 Not Found


This illustrates the behavioral difference between aggregation and containment, specifically the side effect of collection deletion on resources created by the collection in its role as a factory.

1.5 Creating complex collection members

Other proposals, e.g. Henry's, showed ways to nest collections. The example Henry used was a container creating an aggregation. The example suggests/asserts answers to some questions that others have rendered more explicitly, and I think deserve intent-ful discussion.

  1. Should LDP remain silent on the issue of creating members that are anything more than ldp:Resources (i.e. LDPRs as they exist in the current spec)?
    1. Silence is easier for the WG, and it provides no guidance to implementers on how they should implement this behavior should they choose to, so clients have more variation complexity to cope with. The WG might want to "actively stay out of the way" on it, i.e. be careful not to obstruct someone from defining such behavior that is otherwise consistent with LDP, which requires a bit more due diligence than "just not worrying about it at all".
    2. Specifying something informatively risks confusing implementers (like reification did in RDF); if guidance like this is separated into another document (deployment guide?) that risk is lower. It is more work for the WG, but it can be done in parallel with or after Rec-track work.
    3. Specifying something that is normative but optional is more work for the WG, and is on the Rec track, so it might delay the spec. It adds complexity for readers, although whether this is "good" (useful) complexity or not depends on personal value judgements.
    4. My proposal is to consider this as a separate issue, separable from issue 34, and so I will not consider it further here.
  2. Do aggregations aggregations behave differently from containers in any other way?
    1. In the Q&A emails for Henry's proposal, other differences emerged. IIRC a client could not expect to post to the aggregation it created in order to affect membership. Since I had the model described here in my head (where aggregations inherit the "support POST or not" implementation choice from HTTP, and where if they do implement POST then one use for POST is creating new members of the aggregation), I found his response surprising.
    2. My proposal is that the only observable difference in behavior required by LDP is that shown here for DELETE of a non-empty collection.