Object and interaction models

Document model

Carbon LDP™ stores its data in documents, these represent the basic structure to store any resource in your platform. Typically, a document represents a data entity of a given type (e.g. Person, Project, Product, Invoice). It can have any number of literal datatype properties (e.g. string, date, number) and links to other resources. Finally, within Carbon LDP™, documents are uniquely identified by Uniform Resource Identifiers (URIs).

The more you know…

In Carbon LDP™ a Document is a group of quads that share a common context.

 

Also, while document properties can refer to simple values, they can also refer to nested objects by using fragments. It is important that you understand all the parts that conform a document so that you get a good idea of how they can be useful during development.

Properties

As we mentioned before, Carbon LDP™ documents store data in properties. Properties can be named and contain whatever data values your application needs.

Carbon LDP™ manages certain reserved properties that you should be aware of:

  • id: The document’s URI.
  • slug: Holds the last part of the URI the document is identified with. For example, in the URI https://example.com/resource-1/ the slug is resource-1.
  • types: An array holding one or more named classes that describe the type of the document (e.g. Person, Project, Product, Invoice).
  • created: Date when the document was created.
  • modified: Date when the document was last modified.
  • membershipResource: Configures the document where the member documents will be added. On a document it is the document itself, on an access point it is the document the access point belongs to. See Access Points.
  • hasMemberRelation: Configures the property that holds an array containing the members of that document. By default is ldp:Member. See Membership relation.
  • isMemberOfRelation: Configures the property that a member document will acquire when declared as a member of the container document. This property will not exist if the document has no members. See Membership relation.

Bear in mind that some of these, for example created or modified, are System Reserved Properties, which means you can read them but only the platform is allowed to modify them.

URIs

URIs are strings that identify resources in a network. Any URL you can think of is also considered a URI, but not all URIs are URLs. The main difference is that a URL can change the resource it is pointing at, while URIs can also belong to a resource forever (in which case they would be URNs (Unique Resource Names).

Basically, URI = URL + URN

Carbon LDP uses URIs as identifiers because it allows for its documents to be unique, resolvable and relative to the network.

URIs follow a scheme. Carbon LDP™ document URIs, follow the http or https scheme (depending on the platform’s configuration).

Fragments

Fragments are groups of properties that only make sense within the document’s context, useful to represent nested objects. What is more, there are two type of fragments, named fragments or blank nodes (bNodes). The difference between the two of them is that named fragments can be referenced from outside of the document that contains them, whereas bNodes can’t. For this reason the way they are identified also differs.

Named fragments are identified by a URI, relative to the document they belong to. Their URIs have the form of DOCUMENT-URI#NAMED-FRAGMENT-SLUG, but there are times where they can be written relative to the document like #NAMED-FRAGMENT-SLUG.

On the other hand, bNodes are identified by an ID of the form _:RANDOM-STRING. These IDs are local to the document, making it impossible to link to bNodes from outside of the document.

Types

In linked data, all resources can be described with specific types. By default, all Carbon LDP™ Documents will always contain the following types to function properly within the platform:

  • https://carbonldp.com/ns/v1/platform#Document
  • http://www.w3.org/ns/ldp#RDFSource
  • http://www.w3.org/ns/ldp#BasicContainer

Sample document

In the following tabs you will get an example of how a sample document looks in both JSON-LD or TriG. After reading about the different structures a document can contain you should be able to identify them in the following graph of triples.

[
    {
        "@graph": [
        // START: bNode
            {
                "@id": "_:node1c0oqvsupx132",
                "http://example.org/ns#person": [
                    {
                        "@value": "http://localhost:8083/sam-smith/"
                    }
                ],
                "http://example.org/ns#since": [
                    {
                        "@type": "http://www.w3.org/2001/XMLSchema#dateTime",
                        "@value": "2001-10-26T21:32:52.12679"
                    }
                ]
            },
        // END: bNode
        // START: john-doe document
            {
                "@id": "http://localhost:8083/john-doe/",
                "@type": [
                    "http://www.w3.org/ns/ldp#BasicContainer",
                    "https://carbonldp.com/ns/v1/platform#Document",
                    "http://www.w3.org/ns/ldp#RDFSource",
                    "http://example.org/ns#Person"
                ],
                "http://example.org/ns#contact": [      // Property referencing named fragment
                    {
                        "@id": "http://localhost:8083/john-doe/#phones"
                    }
                ],
                "http://example.org/ns#friends": [      // Property referencing bNode
                    {
                        "@id": "_:node1c0oqvsupx132"
                    }
                ],
                "http://example.org/ns#name": [         // Simple property
                    {
                        "@value": "John Doe"
                    }
                ],
                "http://www.w3.org/ns/ldp#hasMemberRelation": [
                    {
                        "@id": "http://www.w3.org/ns/ldp#member"
                    }
                ],
                "http://www.w3.org/ns/ldp#insertedContentRelation": [
                    {
                        "@id": "http://www.w3.org/ns/ldp#MemberSubject"
                    }
                ],
                "http://www.w3.org/ns/ldp#membershipResource": [
                    {
                        "@id": "http://localhost:8083/john-doe/"
                    }
                ],
                "https://carbonldp.com/ns/v1/platform#created": [
                    {
                        "@type": "http://www.w3.org/2001/XMLSchema#dateTime",
                        "@value": "2017-12-07T16:57:58.999-06:00"
                    }
                ],
                "https://carbonldp.com/ns/v1/platform#modified": [
                    {
                        "@type": "http://www.w3.org/2001/XMLSchema#dateTime",
                        "@value": "2017-12-07T16:57:58.999-06:00"
                    }
                ]
            },
        // END: john-doe document
        // START: named fragment
            {
                "@id": "http://localhost:8083/john-doe/#phones",
                "http://example.org/ns#home": [
                    {
                        "@value": "555-4242"
                    }
                ],
                "http://example.org/ns#mobile": [
                    {
                        "@value": "8118-9374"
                    }
                ]
            }
        // END: named fragment
        ],
        "@id": "http://localhost:8083/john-doe/"
    }
]
<http://localhost:8083/john-doe/> {

<!-- START: bNode -->
    _:node1c0oqvsupx132 <http://example.org/ns#person> "http://localhost:8083/sam-smith/" ;
        <http://example.org/ns#since> "2001-10-26T21:32:52.12679"^^<http://www.w3.org/2001/XMLSchema#dateTime> .
<!-- END: bNode -->

<!-- START: john-doe document -->
    <http://localhost:8083/john-doe/>
        a <http://www.w3.org/ns/ldp#BasicContainer> , <https://carbonldp.com/ns/v1/platform#Document> , <http://www.w3.org/ns/ldp#RDFSource> , <http://example.org/ns#Person> ;
        <https://carbonldp.com/ns/v1/platform#created> "2017-12-07T16:57:58.999-06:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
        <https://carbonldp.com/ns/v1/platform#modified> "2017-12-07T16:57:58.999-06:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
        <http://www.w3.org/ns/ldp#membershipResource> <http://localhost:8083/john-doe/> ;
        <http://www.w3.org/ns/ldp#hasMemberRelation> <http://www.w3.org/ns/ldp#member> ;
        <http://www.w3.org/ns/ldp#insertedContentRelation> <http://www.w3.org/ns/ldp#MemberSubject> ;
        <!-- Simple property -->
        <http://example.org/ns#name> "John Doe" ;
        <!-- Property referencing named fragment -->
        <http://example.org/ns#contact> <http://localhost:8083/john-doe/#phones> ;
        <!-- property referencing bNode -->
        <http://example.org/ns#friends> _:node1c0oqvsupx132 .
<!-- END: john-doe document -->

<!-- START: named fragment -->
    <http://localhost:8083/john-doe/#phones>
        <http://example.org/ns#home> "555-4242" ;
        <http://example.org/ns#mobile> "8118-9374" .
<!-- END: named fragment -->

}

If there is anything from the syntax you don’t understand you can check the JSON-LD or TriG W3C specifications, which Carbon LDP complies to.

Try it out…

To see how you can interact with documents in Carbon LDP through REST methods go to Documents.

Relationships in Carbon LDP

Of course, the power of Linked Data relies on the linking of resources. Therefore, a Linked Data Platform must be capable of handling these links or relations between resources in an ordered manner. To achieve this, Carbon LDP divides the relationships into two kinds:

  • Parent-child relation (hard link)
  • Membership relation (soft link)

The more you know…

Links in Carbon LDP are not limited to your application’s domain, therefore you can use readily existing models and public data that form the Semantic Web to enrich your application’s content.

 

Let’s review both types of links and the need for “Access Points”.

Parent-child relation

In Carbon LDP, documents can have children documents. Whenever you create a document, you need a container; this is because Carbon LDP relates the new document to the container by defining it as its direct child. Therefore, everything in Carbon LDP has a parent, even if that is your application’s root resource.

Furthermore, the importance of the hard links comes into play when deleting the documents. Whenever a parent document is deleted, all of its children, and the children of the children (and so on…) will be deleted. On the other hand, this situation does not occur when you are working with soft links.

The more you know…

Carbon LDP Documents work as Basic Containers, therefore listing containment triples and providing a way for creating a containment hierarchy of arbitrary resources.

Membership relation

Unlike a hard link, a soft link is valuable when you want to demonstrate a relationship between two resources that in essence can still be independent; in other words, when you want a document to be a member of another. In this case, when deleting a document, its members won’t be deleted from the platform. Simply, every relationship with the deleted document will disappear from all other documents.

All Carbon LDP documents can maintain a list of members. To achieve this, Carbon LDP uses certain properties in the documents:

  • ldp:membershipResource: Configures the document where the member documents will be added. On a regular document it is the document itself.
  • ldp:hasMemberRelation: Configures the property that holds an array containing the members of that document (by default ldp:members).
  • ldp:isMemberOfRelation: Configures the property that a member document will acquire when declared as a member of the container document (none by default).

By using these properties, Carbon LDP documents can maintain a single list of member documents on their own. However, a document can only maintain one member list through one property, by default ldp:members. Therefore, if you wanted to have members of different types they would get mixed
within the same list.

To prevent this from happening, while allowing you to maintain multiple lists of members per document, Carbon LDP uses Access Points.

Access Point model

Access points are special documents, whose purpose is to maintain a list of members for another document. Documents can have an unlimited number of access points, removing the limitation of lists of members they can maintain. Always remember that access points work as member managers for documents. Therefore, they do not contain member documents themselves.

Furthermore, just as regular documents, access points can maintain unlimited properties in the form of values, links or fragments. However, bear in mind that the most important properties to maintain in an access point are the ones that manage membership relations: ldp:membershipResource, ldp:hasMemberRelation, and ldp:isMemberOfRelation.

The more you know…

A Carbon LDP Access Point can be regarded as equivalent to an LDP Direct Container.

Membership management properties

Carbon LDP complies to the LDP specification when managing relations between resources. While some LDP properties that help manage relations will also be a part of a regular Carbon LDP document, there are certain differences in the way they are defined within access points.

Let’s review the special considerations you should have when working with certain LDP properties within an Carbon LDP access point.

ldp:membershipResource

This property configures the document whose members the access point is managing. In an access point it will always be an external document, which is also where the member documents will be added.

On the other hand, whenever you see this property in a regular Document it should be pointing to itself, since a document is also capable of managing a list of member documents.

ldp:hasMemberRelation

Carbon LDP documents, and therefore access points, can hold a list of member documents in a single property. By default this property is ldp:members. However, this can be configured to personalized properties.

When defining an access point it is essential that you configure this property to a custom one, so that you can manage seperate lists for separate access points. After you add members through your access point, your ldp:membershipResource document will contain those members in the property defined in the access point’s ldp:hasMemberRelation.

ldp:isMemberOfRelation

Links in Carbon LDP can be unidirectional or bidirectional. In an unidirectional relation a document knows the members it contains, but the members are not aware of being related to that document. In contrast, in a bidirectional link a document knows the member it contains, and the members also know they are related to that document.

To achieve a bidirectional relation between resources, you can configure the ldp:isMemberOfRelation property in an access point. The value that you define will become a property in any member document that is added through your access point. Furthermore, the platform will automatically use that property in the member document to relate it back to your ldp:membershipResource document.

Types

In linked data, all resources can be described with specific types. By default, all Carbon LDP Access Points will always contain the following types to function properly within the platform:

  • https://carbonldp.com/ns/v1/platform#Document
  • https://carbonldp.com/ns/v1/platform#AccessPoint
  • http://www.w3.org/ns/ldp#RDFSource
  • http://www.w3.org/ns/ldp#DirectContainer

Sample access point

In the following tabs you will get an example of how a sample access point looks in both JSON-LD or TriG.

[
    {
        "@graph": [
            {
                "@id": "http://localhost:8083/project-x/participants/",
                "@type": [
                    "https://carbonldp.com/ns/v1/platform#AccessPoint",
                    "http://www.w3.org/ns/ldp#DirectContainer",
                    "https://carbonldp.com/ns/v1/platform#Document",
                    "http://www.w3.org/ns/ldp#RDFSource"
                ],
                "http://www.w3.org/ns/ldp#hasMemberRelation": [
                    {
                        "@id": "http://example.org/ns#participant"
                    }
                ],
                "http://www.w3.org/ns/ldp#isMemberOfRelation": [
                    {
                        "@id": "http://example.org/ns#participatesIn"
                    }
                ],
                "http://www.w3.org/ns/ldp#insertedContentRelation": [
                    {
                        "@id": "http://www.w3.org/ns/ldp#MemberSubject"
                    }
                ],
                "http://www.w3.org/ns/ldp#membershipResource": [
                    {
                        "@id": "http://localhost:8083/project-x/"
                    }
                ],
                "https://carbonldp.com/ns/v1/platform#created": [
                    {
                        "@type": "http://www.w3.org/2001/XMLSchema#dateTime",
                        "@value": "2017-12-29T13:19:50.402-06:00"
                    }
                ],
                "https://carbonldp.com/ns/v1/platform#modified": [
                    {
                        "@type": "http://www.w3.org/2001/XMLSchema#dateTime",
                        "@value": "2017-12-29T13:19:50.402-06:00"
                    }
                ]
            }
        ],
        "@id": "http://localhost:8083/project-x/participants/"
    }
]
<http://localhost:8083/project-x/participants/> {
    <http://localhost:8083/project-x/participants/>
        a <https://carbonldp.com/ns/v1/platform#AccessPoint> , <http://www.w3.org/ns/ldp#DirectContainer> , <https://carbonldp.com/ns/v1/platform#Document> , <http://www.w3.org/ns/ldp#RDFSource> ;
        <https://carbonldp.com/ns/v1/platform#created> "2017-12-29T13:19:50.402-06:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
        <https://carbonldp.com/ns/v1/platform#modified> "2017-12-29T13:19:50.402-06:00"^^<http://www.w3.org/2001/XMLSchema#dateTime> ;
        <http://www.w3.org/ns/ldp#membershipResource> <http://localhost:8083/project-x/> ;
        <http://www.w3.org/ns/ldp#hasMemberRelation> <http://example.org/ns#participant> ;
        <http://www.w3.org/ns/ldp#isMemberOfRelation> <http://example.org/ns#participatesIn> ;
        <http://www.w3.org/ns/ldp#insertedContentRelation> <http://www.w3.org/ns/ldp#MemberSubject> .
}

If there is anything from the syntax you don’t understand you can check the JSON-LD or TriG W3C specifications, which Carbon LDP complies to.

Try it out…

To see how you can interact with documents in Carbon LDP through REST methods go to Access Points.

Interaction models

When you interact with a given resource on the Carbon LDP server, you can specify a model that governs how the server behaves with respect to it. A document in Carbon LDP can be treated as a Container or as an RDF Source.

To get a better grasp on this idea, imagine your regular folder and documents system. Folders contain documents, and are therefore considered different entities; they serve a different purpose to that of documents. However, in Carbon LDP everything is always the same entity, a document. In this case, what changes is its behavior given certain situations, between containing other documents or representing something specific, basically being a document.

When you want the server to treat a given document as one type or another, you can specify which model you prefer with an HTTP header in the client request. The preferred interaction model is specified by the HTTP Prefer header, which must have one of the following values:

    • http://www.w3.org/ns/ldp#Container; rel=interaction-model
    • http://www.w3.org/ns/ldp#RDFSource; rel=interaction-model

Container Behavior

When you want the server to treat a document as a Container, use the following interaction model in your request:

Prefer
http://www.w3.org/ns/ldp#Container; rel=interaction-model

As the name implies, Containers contain things. Well, they don’t literally contain things in the same way that folders might, but the concept is similar. A container is itself a document (RDF Source) with triples that link to a set of one or more child or member documents. When a triple describes a parent-child relation it is a containment triple. Moreover, when a triple states a membership relation it is known as a membership triple. So, when you want the server to behave in a way that helps you manage the children or members in a collection, you’ll want to make requests that specify the Container interaction model.

When a document is behaving with the Container interaction model, it can respond to client requests for creation, modification, and/or enumeration of its children and members.

 

In order to help you define the way in which you want to manage the children or members of a container, Carbon LDP has implemented a set of preferences that you can use for different purposes. These are:

  • c:PreferContainer
    • When included, the action will apply to all the document’s occurrences. Therefore, it will affect the document, its children and its relationships with other documents.
  • c:PreferContainmentResources
    • When included, the action will apply to all the resources contained by the document. Basically, all the children documents contained by it.
  • c:PreferContainmentTriples
    • When included, the action will affect the references pointing to the children documents. However, the actual resources will not be affected.
  • c:PreferMembershipResources
    • When included, the action will apply to all the resources that are members of the document. Basically, to all the member documents managed by that container.
  • c:PreferMembershipTriples
    • When included, the action will affect the references pointing to the member documents. However, the actual resources will not be affected.
  • c:PreferSelectedMembershipTriples
    • When included, the action will affect only certain references pointing to the member documents. However, the actual resources will not be affected.

As you might realize, some of these preferences contradict each other. For example, you can’t affect all membership triples and affect only certain membership triples in a single action. Therefore, each of these preferences can be included or omitted from a request in order to specify what triples should be targeted by it. For example, a request that targets only certain membership triples would require the following headers:

Prefer include=https://carbonldp.com/ns/v1/platform#PreferSelectedMembershipTriples

Prefer omit=https://carbonldp.com/ns/v1/platform#PreferMembershipTriples

Whenever there is a case where the platform allows the use of these preferences along with the Container interaction model – to modify multiple documents in a single action – it will be mentioned in the documentation.

A Container is also a document (RDF Source), so while it has a special function as a membership controller, it may also represent additional data. In other words, in addition to having membership and/or containment triples, it can still have a variety of properties or triples that are specific to the resource it represents.

RDF Source Behavior

When you want the server to treat a document as an RDF Source, use the following interaction model in your request:

Prefer http://www.w3.org/ns/ldp#RDFSource; rel=interaction-model

An RDF Source is an RDF graph or the source of one or more arbitrary triples that share the same subject URI. When we use the RDF Source model for a document, we’re generally referring to the document as the resource it represents – some real world entity. You typically prefer this model when you’re working only with the document itself, or properties of the document. When a document is behaving with the RDF Source interaction model, it applies no special features for managing members.

Use the RDF Source interaction model when you’re interested only in the document itself – reading the triples or properties it contains, updating or deleting them, and adding new ones.

You can also use the model to create a document with a given URI that will not be contained by any given Container (i.e. to create an access point).