Advanced document reading
Introduction
We have already covered how you can retrieve a Carbon LDP™ resource with a simple GET
request. Still, applications normally need more than just retrieving a single document. Therefore, we will cover the basics of how to retrieve specific data from your platform using Carbon LDP™’s REST API and SPARQL.
This section of the documentation assumes that you already know how to execute SPARQL queries in Carbon LDP™. If you don’t recall how to do this, please read our documentation on SPARQL querying.
In order to best explain the different ways in which you can use SPARQL in your favor for different application requirements, we initially generated certain data to work with.
First, we generated two containers at the application’s root level, one for books and one for authors. You should end up with something like this:
<http://localhost:8083/books/>
<http://localhost:8083/authors/>
Then, we filled the containers with documents of type ex:Book
and ex:Author
respectively. These documents were defined with the following properties:
ex:Book
ex:name
: String that contains the book’s name.ex:author
:ex:Author
that wrote the book.ex:price
: Integer that represents the cost of the book.
ex:Author
ex:name
: String that contains the author’s name.ex:citizenship
: String that contains the author’s citizenship.
Having these data models in mind, let’s review how you could use different SPARQL functionalities to aid your retrieval of information.
Retrieving only specific properties
It is fairly common for applications to require only certain properties of a document. This can happen, for example, when rendering a list of objects and just displaying their name.
To retrieve only specific properties of a document, you will need to execute a CONSTRUCT SPARQL query. In this case, we will try to retrieve all the documents stored in our book’s container to render a list of their names.
Create the POST request
Create the following HTTP request to execute a SPARQL query on the platform.
POST http://localhost:8083/
HTTP Header | Value | Required/Optional |
---|---|---|
Content-Type | application/sparql-query | Required |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts | Optional (strongly recommended) |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums | Optional (strongly recommended) |
Accept | application/ld+json | Optional (defaults to text/turtle ) |
PREFIX ex: <http://example.org/ns#>
PREFIX ldp: <http://www.w3.org/ns/ldp#>
CONSTRUCT {
?book
ex:name ?bookName .
}
WHERE {
<http://localhost:8083/books/> ldp:contains ?book .
OPTIONAL { ?book ex:name ?bookName } .
}
Review the POST request
It is important that before issuing this request, you understand all its parts. Next, you’ll get more information about each part in the request.
Content-Type
Since the request method is POST it requires a body. Therefore, the Content-Type HTTP header tells the platform what kind of content to expect in the body of the request. In the examples we use application/sparql-query
(SPARQL) because we are describing a SPARQL query that we need the platform to execute.
Note that it is essential that you include this header with the appropriate value. Otherwise, if you include the header with a valid value other than application/sparql-query
your request might be accepted by the platform and a new document can be accidentally created, instead of running a SPARQL query.
Accept
Because of the different results that can be obtained from an SPARQL query, this header will vary depending on the query form that you are executing.
Since we are executing a CONSTRUCT
query, we will receive RDF graphs as a result. Hence, the platform’s response can include different RDF Dataset Languages supported by Carbon LDP. These include:
- CONSTRUCT: RDF Dataset Languages like:
- JSON-LD:
application/ld+json
- TriG:
application/trig
- Turtle:
application/turtle
- RDF XML:
application/rdf+xml
- JSON-LD:
Prefer
In this case, we strongly recommend the usage of the following preference headers:
include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
- Ensures that every property retrieved via a
CONSTRUCT
query is contained within a context. include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
- Includes the checksums of the resources you are retrieving in the
c:checksum
property.
It is important to stand out that CONSTRUCT
queries don’t return contexts. This is an issue if you’re trying to work with only certain properties of a Carbon LDP document. In Carbon LDP, all properties live within the context of the document that contains them. If a property is not a part of the context in which Carbon LDP stores it, you could be building content that does not exist in your database. To avoid this, we recommend you always include the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header.
Furthermore, we also recommend including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header. Having the resource’s checksums will help you ensure that the data you are modifying is accurate before changing anything within your document; this is necessary to maintain data consistency.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Also, note that including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header without the include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header will not allow you to retrieve the document’s checksums.
To learn how to retrieve a document’s checksum without using the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header, go to this section.
Body
The body of the request is a SPARQL query. For this example we are executing a CONSTRUCT
query that aims to retrieve only certain properties from all the documents contained in a specific resource. In this case, the query will retrieve all documents that are contained by the resource <http://localhost:8083/books/
.
Note that we enclose the property ex:name
in an OPTIONAL
pattern. Basically, any resource that complies with the rest of the patterns specified in the query will be returned in the final result; regardless of the resource not containing a property specified within an optional clause. Finally, if the remaining resources have a ex:name
property, it will be included in the result.
As a direct user of the REST API you should be aware of the freedom CONSTRUCT
queries provide. You could end up creating valid RDF graphs that are not actually contained within your database. To prevent this from happening we encourage you to always review the CONSTRUCT
portion of your query. Be sure that you are building documents that comply with your application’s object model.
If there is anything from the request body you don’t understand you can check the SPARQL W3C specifications, which Carbon LDP complies to.
Issue the POST request
A successful request will result in HTTP status code 200 OK.
HTTP Header | Value |
---|---|
Content-Type |
application/ld+json
|
Preference-Applied |
include="https://carbonldp.com/ns/v1/platform#PreferResultsContexts" and / or include="https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums"
|
As part of the response headers:
- The Content-Type will describe the format in which the result of the query is returned. If you set an Accept header for your request it will conform to this format.
- The Preference-Applied will describe the preferences applied by the platform when executing your request. If you set a Prefer header for your request and the platform applied it, the value of that Prefer header will be included.
Review the query result
Furthermore, the response body will contain the result obtained from your query. Naturally, this result may vary depending on the documents that you have in your platform when running the query. For this example, you should get something like this:
[
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-1/",
"http://example.org/ns#name": [
{
"@value": "Book 1"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-258015764"
}
]
}
],
"@id": "http://localhost:8083/books/book-1/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-2/",
"http://example.org/ns#name": [
{
"@value": "Book 2"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-526036773"
}
]
}
],
"@id": "http://localhost:8083/books/book-2/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-3/",
"http://example.org/ns#name": [
{
"@value": "Book 3"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-391739953"
}
]
}
],
"@id": "http://localhost:8083/books/book-3/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-4/",
"http://example.org/ns#name": [
{
"@value": "Book 4"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "440089371"
}
]
}
],
"@id": "http://localhost:8083/books/book-4/"
}
]
The platform returns a graph with the documents that matched your query, along with the specific properties that were requested. Also, note that for every document returned, the platform added the c:checksum
property with its corresponding value.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Retrieving only documents of a specific type
A document can store any type of documents as its children/members, but most of the time, applications only care about documents that follow a particular shape. Or said in other words, have a specific type.
To retrieve only specific properties of document’s with a specific type, you will need to execute a CONSTRUCT SPARQL query. In this case, we will try to retrieve all the documents of type ex:Book
to render a list of their names.
Create the POST request
Create the following HTTP request to execute a SPARQL query on the platform.
POST http://localhost:8083/
HTTP Header | Value | Required/Optional |
---|---|---|
Content-Type | application/sparql-query | Required |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts | Optional (strongly recommended) |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums | Optional (strongly recommended) |
Accept | application/ld+json | Optional (defaults to text/turtle ) |
PREFIX ex: <http://example.org/ns#>
CONSTRUCT {
?book
ex:name ?bookName .
}
WHERE {
?book a ex:Book .
OPTIONAL { ?book ex:name ?bookName } .
}
Review the POST request
It is important that before issuing this request, you understand all its parts. Next, you’ll get more information about each part in the request.
Content-Type
Since the request method is POST it requires a body. Therefore, the Content-Type HTTP header tells the platform what kind of content to expect in the body of the request. In the examples we use application/sparql-query
(SPARQL) because we are describing a SPARQL query that we need the platform to execute.
Note that it is essential that you include this header with the appropriate value. Otherwise, if you include the header with a valid value other than application/sparql-query
your request might be accepted by the platform and a new document can be accidentally created, instead of running a SPARQL query.
Accept
Because of the different results that can be obtained from an SPARQL query, this header will vary depending on the query form that you are executing.
Since we are executing a CONSTRUCT
query, we will receive RDF graphs as a result. Hence, the platform’s response can include different RDF Dataset Languages supported by Carbon LDP. These include:
- CONSTRUCT: RDF Dataset Languages like:
- JSON-LD:
application/ld+json
- TriG:
application/trig
- Turtle:
application/turtle
- RDF XML:
application/rdf+xml
- JSON-LD:
Prefer
In this case, we strongly recommend the usage of the following preference headers:
include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
- Ensures that every property retrieved via a
CONSTRUCT
query is contained within a context. include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
- Includes the checksums of the resources you are retrieving in the
c:checksum
property.
It is important to stand out that CONSTRUCT
queries don’t return contexts. This is an issue if you’re trying to work with only certain properties of a Carbon LDP document. In Carbon LDP, all properties live within the context of the document that contains them. If a property is not a part of the context in which Carbon LDP stores it, you could be building content that does not exist in your database. To avoid this, we recommend you always include the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header.
Furthermore, we also recommend including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header. Having the resource’s checksums will help you ensure that the data you are modifying is accurate before changing anything within your document; this is necessary to maintain data consistency.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Also, note that including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header without the include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header will not allow you to retrieve the document’s checksums.
To learn how to retrieve a document’s checksum without using the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header, go to this section.
Body
The body of the request is a SPARQL query. For this example we are executing a CONSTRUCT
query that aims to retrieve only certain properties from all the documents of a certain type. In this case, the query will retrieve all documents of type ex:Book
.
Note that we enclose the property ex:name
in an OPTIONAL
pattern. Basically, any resource that complies with the rest of the patterns specified in the query will be returned in the final result; regardless of the resource not containing a property specified within an optional clause. Finally, if the remaining resources have a ex:name
property, it will be included in the result.
As a direct user of the REST API you should be aware of the freedom CONSTRUCT
queries provide. You could end up creating valid RDF graphs that are not actually contained within your database. To prevent this from happening we encourage you to always review the CONSTRUCT
portion of your query. Be sure that you are building documents that comply with your application’s object model.
If there is anything from the request body you don’t understand you can check the SPARQL W3C specifications, which Carbon LDP complies to.
Issue the POST request
A successful request will result in HTTP status code 200 OK.
HTTP Header | Value |
---|---|
Content-Type |
application/ld+json
|
Preference-Applied |
include="https://carbonldp.com/ns/v1/platform#PreferResultsContexts" and / or include="https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums"
|
As part of the response headers:
- The Content-Type will describe the format in which the result of the query is returned. If you set an Accept header for your request it will conform to this format.
- The Preference-Applied will describe the preferences applied by the platform when executing your request. If you set a Prefer header for your request and the platform applied it, the value of that Prefer header will be included.
Review the query result
Furthermore, the response body will contain the result obtained from your query. Naturally, this result may vary depending on the documents that you have in your platform when running the query. For this example, you should get something like this:
[
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-1/",
"http://example.org/ns#name": [
{
"@value": "Book 1"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-258015764"
}
]
}
],
"@id": "http://localhost:8083/books/book-1/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-2/",
"http://example.org/ns#name": [
{
"@value": "Book 2"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-526036773"
}
]
}
],
"@id": "http://localhost:8083/books/book-2/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-3/",
"http://example.org/ns#name": [
{
"@value": "Book 3"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-391739953"
}
]
}
],
"@id": "http://localhost:8083/books/book-3/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-4/",
"http://example.org/ns#name": [
{
"@value": "Book 4"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "440089371"
}
]
}
],
"@id": "http://localhost:8083/books/book-4/"
}
]
The platform returns a graph with the documents that matched your query, along with the specific properties that were requested. Also, note that for every document returned, the platform added the c:checksum
property with its corresponding value.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Filtering documents
The previous sections have detailed how to filter documents based on their location in your platform’s structure or their types, but it is fairly common for applications to need to filter them based on their properties instead (or more complex conditions).
To achieve this we can use SPARQL’s FILTER
expression. You can find more about it here. In this case, we will try to retrieve all the documents of type ex:Book
which ex:price
is greater than $5 to render a list of their names.
Create the POST request
Create the following HTTP request to execute a SPARQL query on the platform.
POST http://localhost:8083/
HTTP Header | Value | Required/Optional |
---|---|---|
Content-Type | application/sparql-query | Required |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts | Optional (strongly recommended) |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums | Optional (strongly recommended) |
Accept | application/ld+json | Optional (defaults to text/turtle ) |
PREFIX ex: <http://example.org/ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
CONSTRUCT {
?book
ex:name ?bookName ;
ex:price ?bookPrice .
}
WHERE {
?book a ex:Book .
OPTIONAL { ?book ex:name ?bookName } .
?book ex:price ?bookPrice .
FILTER ( ?bookPrice > xsd:integer( "5" ) )
}
Review the POST request
It is important that before issuing this request, you understand all its parts. Next, you’ll get more information about each part in the request.
Content-Type
Since the request method is POST it requires a body. Therefore, the Content-Type HTTP header tells the platform what kind of content to expect in the body of the request. In the examples we use application/sparql-query
(SPARQL) because we are describing a SPARQL query that we need the platform to execute.
Note that it is essential that you include this header with the appropriate value. Otherwise, if you include the header with a valid value other than application/sparql-query
your request might be accepted by the platform and a new document can be accidentally created, instead of running a SPARQL query.
Accept
Because of the different results that can be obtained from an SPARQL query, this header will vary depending on the query form that you are executing.
Since we are executing a CONSTRUCT
query, we will receive RDF graphs as a result. Hence, the platform’s response can include different RDF Dataset Languages supported by Carbon LDP. These include:
- CONSTRUCT: RDF Dataset Languages like:
- JSON-LD:
application/ld+json
- TriG:
application/trig
- Turtle:
application/turtle
- RDF XML:
application/rdf+xml
- JSON-LD:
Prefer
In this case, we strongly recommend the usage of the following preference headers:
include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
- Ensures that every property retrieved via a
CONSTRUCT
query is contained within a context. include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
- Includes the checksums of the resources you are retrieving in the
c:checksum
property.
It is important to stand out that CONSTRUCT
queries don’t return contexts. This is an issue if you’re trying to work with only certain properties of a Carbon LDP document. In Carbon LDP, all properties live within the context of the document that contains them. If a property is not a part of the context in which Carbon LDP stores it, you could be building content that does not exist in your database. To avoid this, we recommend you always include the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header.
Furthermore, we also recommend including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header. Having the resource’s checksums will help you ensure that the data you are modifying is accurate before changing anything within your document; this is necessary to maintain data consistency.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Also, note that including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header without the include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header will not allow you to retrieve the document’s checksums.
To learn how to retrieve a document’s checksum without using the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header, go to this section.
Body
The body of the request is a SPARQL query. For this example we are executing a CONSTRUCT
query that aims to retrieve only certain properties from all the documents of a specific type, that comply with the condition set within the FILTER
expression. In this case, the query will retrieve all documents of type ex:Book
. It will retrieve the ex:price
property and will filter out the ones that are $5 or less.
Note that we enclose the property ex:name
in an OPTIONAL
pattern. Basically, any resource that complies with the rest of the patterns specified in the query will be returned in the final result; regardless of the resource not containing a property specified within an optional clause. Finally, if the remaining resources have a ex:name
property, it will be included in the result.
As a general rule, we recommend that any property used within a FILTER
expression is not enclosed within an OPTIONAL
pattern.
As a direct user of the REST API you should be aware of the freedom CONSTRUCT
queries provide. You could end up creating valid RDF graphs that are not actually contained within your database. To prevent this from happening we encourage you to always review the CONSTRUCT
portion of your query. Be sure that you are building documents that comply with your application’s object model.
If there is anything from the request body you don’t understand you can check the SPARQL W3C specifications, which Carbon LDP complies to.
Issue the POST request
A successful request will result in HTTP status code 200 OK.
HTTP Header | Value |
---|---|
Content-Type |
application/ld+json
|
Preference-Applied |
include="https://carbonldp.com/ns/v1/platform#PreferResultsContext" and / or include="https://carbonldp.com/ns/v1/platform#PreferDocumentETags"
|
As part of the response headers:
- The Content-Type will describe the format in which the result of the query is returned. If you set an Accept header for your request it will conform to this format.
- The Preference-Applied will describe the preferences applied by the platform when executing your request. If you set a Prefer header for your request and the platform applied it, the value of that Prefer header will be included.
Review the query result
Furthermore, the response body will contain the result obtained from your query. Naturally, this result may vary depending on the documents that you have in your platform when running the query. For this example, you should get something like this:
[
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-1/",
"http://example.org/ns#name": [
{
"@value": "Book 1"
}
],
"http://example.org/ns#price": [
{
"@type": "http://www.w3.org/2001/XMLSchema#integer",
"@value": "10"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-258015764"
}
]
}
],
"@id": "http://localhost:8083/books/book-1/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-3/",
"http://example.org/ns#name": [
{
"@value": "Book 3"
}
],
"http://example.org/ns#price": [
{
"@type": "http://www.w3.org/2001/XMLSchema#integer",
"@value": "7"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-391739953"
}
]
}
],
"@id": "http://localhost:8083/books/book-3/"
}
]
The platform returns a graph with the documents that matched your query, along with the specific properties that were requested. Also, note that for every document returned, the platform added the c:checksum
property with its corresponding value.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Paging through documents
Sometimes collections can get very big and retrieving them all together on a single request can take a long time (or even crash).
To avoid this we can use SPARQL’s LIMIT
and OFFSET
expressions. In this case, we will try to retrieve the second and third most expensive books to render a list of their names and prices.
Create the POST request
Create the following HTTP request to execute a SPARQL query on the platform.
POST http://localhost:8083/
HTTP Header | Value | Required/Optional |
---|---|---|
Content-Type | application/sparql-query | Required |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts | Optional (strongly recommended) |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums | Optional (strongly recommended) |
Accept | application/ld+json | Optional (defaults to text/turtle ) |
PREFIX ex: <http://example.org/ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
CONSTRUCT {
?book
ex:name ?bookName ;
ex:price ?bookPrice .
}
WHERE {
{
SELECT DISTINCT ?book {
?book a ex:Book .
?book ex:price ?bookPrice .
}
ORDER BY DESC ( ?bookPrice )
LIMIT 2
OFFSET 1
}
OPTIONAL { ?book ex:name ?bookName } .
?book ex:price ?bookPrice .
}
Review the POST request
It is important that before issuing this request, you understand all its parts. Next, you’ll get more information about each part in the request.
Content-Type
Since the request method is POST it requires a body. Therefore, the Content-Type HTTP header tells the platform what kind of content to expect in the body of the request. In the examples we use application/sparql-query
(SPARQL) because we are describing a SPARQL query that we need the platform to execute.
Note that it is essential that you include this header with the appropriate value. Otherwise, if you include the header with a valid value other than application/sparql-query
your request might be accepted by the platform and a new document can be accidentally created, instead of running a SPARQL query.
Accept
Because of the different results that can be obtained from an SPARQL query, this header will vary depending on the query form that you are executing.
Since we are executing a CONSTRUCT
query, we will receive RDF graphs as a result. Hence, the platform’s response can include different RDF Dataset Languages supported by Carbon LDP. These include:
- CONSTRUCT: RDF Dataset Languages like:
- JSON-LD:
application/ld+json
- TriG:
application/trig
- Turtle:
application/turtle
- RDF XML:
application/rdf+xml
- JSON-LD:
Prefer
In this case, we strongly recommend the usage of the following preference headers:
include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
- Ensures that every property retrieved via a
CONSTRUCT
query is contained within a context. include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
- Includes the checksums of the resources you are retrieving in the
c:checksum
property.
It is important to stand out that CONSTRUCT
queries don’t return contexts. This is an issue if you’re trying to work with only certain properties of a Carbon LDP document. In Carbon LDP, all properties live within the context of the document that contains them. If a property is not a part of the context in which Carbon LDP stores it, you could be building content that does not exist in your database. To avoid this, we recommend you always include the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header.
Furthermore, we also recommend including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header. Having the resource’s checksums will help you ensure that the data you are modifying is accurate before changing anything within your document; this is necessary to maintain data consistency.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Also, note that including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header without the include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header will not allow you to retrieve the document’s checksums.
To learn how to retrieve a document’s checksum without using the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header, go to this section.
Body
The body of the request is a SPARQL query. For this example we are executing a CONSTRUCT
query that aims to retrieve a limited number of resources, of a specific type, and with only certain properties. In this case, the query will retrieve the subjects of a limited number of documents of type ex:Book
via a sub-select.
This SELECT
retrieves the resources that comply with having a specified type and property. Then, they are ordered by the property stated in the ORDER BY DESC
clause. Note that the default declaration in SPARQL is ORDER BY
, which executes an ascending ordering of results.
Afterwards, the ordered results will skip the number of entries specified by the OFFSET
pattern and the number of subjects retrieved will be limited by the LIMIT
clause. For simplicity, we recommend executing all of these within a sub-select that only retrieves the subjects of the resources that comply to the properties you are looking for. Afterwards, you can use these subjects to CONSTRUCT
the specific information you want to get from them.
Note that we enclose the property ex:name
in an OPTIONAL
pattern. Basically, any resource that complies with the rest of the patterns specified in the query will be returned in the final result; regardless of the resource not containing a property specified within an optional clause. Finally, if the remaining resources have a ex:name
property, it will be included in the result.
As a direct user of the REST API you should be aware of the freedom CONSTRUCT
queries provide. You could end up creating valid RDF graphs that are not actually contained within your database. To prevent this from happening we encourage you to always review the CONSTRUCT
portion of your query. Be sure that you are building documents that comply with your application’s object model.
If there is anything from the request body you don’t understand you can check the SPARQL W3C specifications, which Carbon LDP complies to.
[
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-2/",
"http://example.org/ns#name": [
{
"@value": "Book 2"
}
],
"http://example.org/ns#price": [
{
"@type": "http://www.w3.org/2001/XMLSchema#integer",
"@value": "3"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-526036773"
}
]
}
],
"@id": "http://localhost:8083/books/book-2/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-3/",
"http://example.org/ns#name": [
{
"@value": "Book 3"
}
],
"http://example.org/ns#price": [
{
"@type": "http://www.w3.org/2001/XMLSchema#integer",
"@value": "7"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-391739953"
}
]
}
],
"@id": "http://localhost:8083/books/book-3/"
}
]
The platform returns a graph with the documents that matched your query, along with the specific properties that were requested. Also, note that for every document returned, the platform added the c:checksum
property with its corresponding value.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Retrieving nested objects
So far we have covered only simple object structures. But sometimes an application needs to retrieve a more complex structure, one that contains nested objects.
Retrieving connected objects can be accomplished by a SPARQL CONSTRUCT
query. In this case, we will try to retrieve all documents of type ex:Book
to render a list of their names and their author’s names.
Create the POST request
Create the following HTTP request to execute a SPARQL query on the platform.
POST http://localhost:8083/
HTTP Header | Value | Required/Optional |
---|---|---|
Content-Type | application/sparql-query | Required |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts | Optional (strongly recommended) |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums | Optional (strongly recommended) |
Accept | application/ld+json | Optional (defaults to text/turtle ) |
PREFIX ex: <http://example.org/ns#>
CONSTRUCT {
?book
ex:name ?bookName ;
ex:author ?author .
?author ex:name ?authorName .
}
WHERE {
?book a ex:Book .
OPTIONAL { ?book ex:name ?bookName } .
OPTIONAL{
?book ex:author ?author .
?author ex:name ?authorName .
} .
}
Review the POST request
It is important that before issuing this request, you understand all its parts. Next, you’ll get more information about each part in the request.
Content-Type
Since the request method is POST it requires a body. Therefore, the Content-Type HTTP header tells the platform what kind of content to expect in the body of the request. In the examples we use application/sparql-query
(SPARQL) because we are describing a SPARQL query that we need the platform to execute.
Note that it is essential that you include this header with the appropriate value. Otherwise, if you include the header with a valid value other than application/sparql-query
your request might be accepted by the platform and a new document can be accidentally created, instead of running a SPARQL query.
Accept
Because of the different results that can be obtained from an SPARQL query, this header will vary depending on the query form that you are executing.
Since we are executing a CONSTRUCT
query, we will receive RDF graphs as a result. Hence, the platform’s response can include different RDF Dataset Languages supported by Carbon LDP. These include:
- CONSTRUCT: RDF Dataset Languages like:
- JSON-LD:
application/ld+json
- TriG:
application/trig
- Turtle:
application/turtle
- RDF XML:
application/rdf+xml
- JSON-LD:
Prefer
In this case, we strongly recommend the usage of the following preference headers:
include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
- Ensures that every property retrieved via a
CONSTRUCT
query is contained within a context. include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
- Includes the checksums of the resources you are retrieving in the
c:checksum
property.
It is important to stand out that CONSTRUCT
queries don’t return contexts. This is an issue if you’re trying to work with only certain properties of a Carbon LDP document. In Carbon LDP, all properties live within the context of the document that contains them. If a property is not a part of the context in which Carbon LDP stores it, you could be building content that does not exist in your database. To avoid this, we recommend you always include the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header.
Furthermore, we also recommend including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header. Having the resource’s checksums will help you ensure that the data you are modifying is accurate before changing anything within your document; this is necessary to maintain data consistency.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Also, note that including the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header without the include=https://carbonldp.com/ns/v1/platform#PreferResultsContexts
header will not allow you to retrieve the document’s checksums.
To learn how to retrieve a document’s checksum without using the Prefer, include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums
header, go to this section.
Body
The body of the request is a SPARQL query. For this example we are executing a CONSTRUCT
query that aims to retrieve all the resources of a specific type, including certain properties that point to nested objects, and specific properties from these objects. In this case, the query will retrieve all the documents of type ex:Book
.
Note that we enclose the property ex:name
in an OPTIONAL
pattern. Basically, any resource that complies with the rest of the patterns specified in the query will be returned in the final result; regardless of the resource not containing a property specified within an optional clause. Finally, if the remaining resources have a ex:name
property, it will be included in the result.
Here, we are using an OPTIONAL
statement that includes multiple statements. We know that the property ex:author
points to another resource, rather than a simple value. Therefore, we want to make sure that the property is only included if the nested resource has a property ex:name
. Otherwise, our result would point to the correct resource, but the name, which is a property we want to retrieved, would not be included.
As a direct user of the REST API you should be aware of the freedom CONSTRUCT
queries provide. You could end up creating valid RDF graphs that are not actually contained within your database. To prevent this from happening we encourage you to always review the CONSTRUCT
portion of your query. Be sure that you are building documents that comply with your application’s object model.
If there is anything from the request body you don’t understand you can check the SPARQL W3C specifications, which Carbon LDP complies to.
Issue the POST request
A successful request will result in HTTP status code 200 OK.
HTTP Header | Value |
---|---|
Content-Type |
application/ld+json
|
Preference-Applied |
include="https://carbonldp.com/ns/v1/platform#PreferResultsContext" and / or include="https://carbonldp.com/ns/v1/platform#PreferDocumentETags"
|
As part of the response headers:
- The Content-Type will describe the format in which the result of the query is returned. If you set an Accept header for your request it will conform to this format.
- The Preference-Applied will describe the preferences applied by the platform when executing your request. If you set a Prefer header for your request and the platform applied it, the value of that Prefer header will be included.
Review the query result
Furthermore, the response body will contain the result obtained from your query. Naturally, this result may vary depending on the documents that you have in your platform when running the query. For this example, you should get something like this:
[
{
"@graph": [
{
"@id": "http://localhost:8083/authors/author-1/",
"http://example.org/ns#name": [
{
"@value": "Author 1"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-402392604"
}
]
}
],
"@id": "http://localhost:8083/authors/author-1/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/authors/author-2/",
"http://example.org/ns#name": [
{
"@value": "Author 2"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "743946608"
}
]
}
],
"@id": "http://localhost:8083/authors/author-2/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-1/",
"http://example.org/ns#author": [
{
"@id": "http://localhost:8083/authors/author-1/"
}
],
"http://example.org/ns#name": [
{
"@value": "Book 1"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-258015764"
}
]
}
],
"@id": "http://localhost:8083/books/book-1/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-2/",
"http://example.org/ns#author": [
{
"@id": "http://localhost:8083/authors/author-2/"
}
],
"http://example.org/ns#name": [
{
"@value": "Book 2"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-526036773"
}
]
}
],
"@id": "http://localhost:8083/books/book-2/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-3/",
"http://example.org/ns#name": [
{
"@value": "Book 3"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-1646761005"
}
]
}
],
"@id": "http://localhost:8083/books/book-3/"
},
{
"@graph": [
{
"@id": "http://localhost:8083/books/book-4/",
"http://example.org/ns#author": [
{
"@id": "http://localhost:8083/authors/author-1/"
}
],
"http://example.org/ns#name": [
{
"@value": "Book 4"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "440089371"
}
]
}
],
"@id": "http://localhost:8083/books/book-4/"
}
]
The platform returns a graph with the documents that matched your query, along with the specific properties that were requested. Also, note that for every document returned, the platform added the c:checksum
property with its corresponding value.
Bear in mind that the property c:checksum
is not contained within your database, its only generated when requested. What is more, it acts as a System Managed Property, which means you will only be able to read it, but not modify it.
Improving performance when retrieving checksums
To be able to return a document’s checksum, the platform needs to know the document’s context. While the simplest way of obtaining this is including the Prefer, include="https://carbonldp.com/ns/v1/platform#PreferResultsContexts"
header, this may hinder the platform’s performance in large data sets. The following request will detail how to obtain a document’s cheksum without necessarily retrieving its context.
POST http://localhost:8083/
HTTP Header | Value | Required/Optional |
---|---|---|
Content-Type | application/sparql-query | Required |
Prefer | include=https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums | Required |
Accept | application/ld+json | Optional (defaults to text/turtle ) |
PREFIX ex: <http://example.org/ns#>
PREFIX ldp: <http://www.w3.org/ns/ldp#>
PREFIX c: <https://carbonldp.com/ns/v1/platform#>
CONSTRUCT {
?book
ex:name ?bookName ;
ex:author ?bookAuthor ;
c:document ?bookDocument .
}
WHERE {
<http://localhost:8083/books/> ldp:contains ?book .
GRAPH ?bookDocument { ?book ex:name ?bookName } .
OPTIONAL { ?book ex:author ?bookAuthor } .
}
In your request body, you will need to include the GRAPH
keyword, which lets you match patterns against named graphs. When including the name of that graph in the c:document
property in your CONSTRUCT
query, you are letting the platform know which document you are retrieving; allowing it to obtains its corresponding checksum.
It is mandatory that your CONSTRUCT
query matches the ?subject c:document ?document
pattern to retrieve the document’s checksum.
Also, if your query contains mandatory triples, including one of those triples within the GRAPH
keyword will suffice. However, if all the properties your query includes are OPTIONAL
, we recommend you include the GRAPH
keyword in all of them.
For example, if you were only requesting an OPTIONAL
book author, your query would look like this:
PREFIX ex: <http://example.org/ns#>
PREFIX ldp: <http://www.w3.org/ns/ldp#>
PREFIX c: <https://carbonldp.com/ns/v1/platform#>
CONSTRUCT {
?book
ex:author ?bookAuthor ;
c:document ?bookDocument .
}
WHERE {
<http://localhost:8083/books/> ldp:contains ?book .
OPTIONAL { GRAPH ?bookDocument { ?book ex:author ?bookAuthor } } .
}
A successful request will result in HTTP status code 200 OK.
HTTP Header | Value |
---|---|
Preference-Applied |
include="https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums"
|
Overall, this request will allow you to obtain a document’s checksum by only adding the Prefer, include="https://carbonldp.com/ns/v1/platform#PreferDocumentChecksums"
header. The response body you obtain will vary depending on the information stored in your platform, but it should look similar to this:
[
{
"@id": "http://localhost:8083/books/book-1/",
"http://example.org/ns#author": [
{
"@id": "http://localhost:8083/authors/author-1/"
}
],
"http://example.org/ns#name": [
{
"@value": "Book 1"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-258015764"
}
],
"https://carbonldp.com/ns/v1/platform#document": [
{
"@id": "http://localhost:8083/books/book-1/"
}
]
},
{
"@id": "http://localhost:8083/books/book-2/",
"http://example.org/ns#author": [
{
"@id": "http://localhost:8083/authors/author-2/"
}
],
"http://example.org/ns#name": [
{
"@value": "Book 2"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-526036773"
}
],
"https://carbonldp.com/ns/v1/platform#document": [
{
"@id": "http://localhost:8083/books/book-2/"
}
]
},
{
"@id": "http://localhost:8083/books/book-3/",
"http://example.org/ns#name": [
{
"@value": "Book 3"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "-1646761005"
}
],
"https://carbonldp.com/ns/v1/platform#document": [
{
"@id": "http://localhost:8083/books/book-3/"
}
]
},
{
"@id": "http://localhost:8083/books/book-4/",
"http://example.org/ns#author": [
{
"@id": "http://localhost:8083/authors/author-1/"
}
],
"http://example.org/ns#name": [
{
"@value": "Book 4"
}
],
"https://carbonldp.com/ns/v1/platform#checksum": [
{
"@value": "440089371"
}
],
"https://carbonldp.com/ns/v1/platform#document": [
{
"@id": "http://localhost:8083/books/book-4/"
}
]
}
]
Please note that the result retrieved with this query is not contained within a graph. In order to later use this information with the platform, you should parse it into a valid format. Finally, bear in mind that the properties c:checksum
and c:document
are not contained within your database and act as System Managed Properties, which means you will only be able to read them, but not modify them.
Conclusion
By executing more complex SPARQL queries, the application can control the data it is going to retrieve and reduce the number of requests it executes. Furthermore, via different Prefer headers, Carbon LDP provides all the necessary information to work with partial documents through the REST API. However, this functionality should be used responsibly given the amount of freedom SPARQL provides when building RDF graphs. Be sure that you always build documents that comply with your application’s object model.
Normally, developers will prefer use of the Carbon LDP™ Workbench (GUI) and an SDK, which together simplify the process of building and working with the platform. Still, all functions of the platform can be accessed through the REST API and those developers who understand the REST API may find it advantageous to use in some cases.