Skip to content
This repository was archived by the owner on Apr 13, 2022. It is now read-only.

Latest commit

 

History

History
382 lines (299 loc) · 11.8 KB

File metadata and controls

382 lines (299 loc) · 11.8 KB

Solid HTTPS REST API Spec

Note: This spec is a component of the parent Solid specification; the parent spec and all its components are versioned as a whole.

Reading Resources

Resources can be commonly accessed (i.e. read) using HTTP GET requests. Solid servers are encouraged to perform content negotiation for RDF resources, depending on the value of the Accept header.

IMPORTANT: a default Content-Type: text/turtle will be used for requests for RDF resources or views (containers) that do not have an Accept header.

Streams

Being LDP (BasicContainer) compliant, Solid servers MUST return a full listing of container contents when receiving requests for containers. For every resource in a container, a Solid server may include additional metadata, such as the time the resource was modified, the size of the resource, and more importantly any other RDF type specified for the resource in its metadata. You will notice in the example below that the <profile> resource has the extra RDF type <http://xmlns.com/foaf/0.1/PersonalProfileDocument>, and also that the resource <workspace/> has the RDF type <http://www.w3.org/ns/pim/space#Workspace>.

Extra metadata can also be added, describing whether each resource in the container maps to a file or a directory on the server, using the POSIX vocabulary. Here is an example that reflects how our current server implementations handle such a request:

REQUEST:

GET /
Host: example.org

RESPONSE:

HTTP/1.1 200 OK
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .

<>
    a <http://www.w3.org/ns/ldp#BasicContainer>, <http://www.w3.org/ns/ldp#Container>, <http://www.w3.org/ns/posix/stat#Directory> ;
    <http://www.w3.org/ns/ldp#contains> <profile>, <data/>, <workspace/> ;
    <http://www.w3.org/ns/posix/stat#mtime> "1436281776" ;
    <http://www.w3.org/ns/posix/stat#size> "4096" .

<profile>
    a <http://xmlns.com/foaf/0.1/PersonalProfileDocument>, <http://www.w3.org/ns/posix/stat#File> ;
    <http://www.w3.org/ns/posix/stat#mtime> "1434583075" ;
    <http://www.w3.org/ns/posix/stat#size> "780" .

Globbing (GET the merged RDF graph of a container)

Note: this feature is at risk of being changed or removed. Please join the discussion. Code depending on this will still work for now.

To optimize certain applications, this specification defines a single GET operation that provides access to an aggregation of the RDF resources in a container. We refer to this feature as globbing, since it provides a subset of the functionality offered by the UNIX shell glob. Consider a container to which the user has Read access, which will have a URL ending in /. If we append a * to that URL (so it ends in /*), we obtain the URL of a resource that, in response to a GET request, returns the RDF graph merge of all of the container's direct child resources that are available in an RDF format and for which the user has Read access. Resources with syntax errors can be ignored or be partially included, but they do not cause a failure. The response can contain additional metadata about the container, such as the list of resources.

For example, consider a container /data that contains the following resources:

  • resource1.ttl
  • resource2.ttl
  • hidden3.ttl
  • resource4.txt

The user performing the request had read access to /data, resource1.ttl and resource2.ttl, but not to hidden3.ttl. Let's assume that /data/resource1.ttl and /data/resource2.ttl contain one triple each:

<> a <https://example.org/ns/type#One> .
<> a <https://example.org/ns/type#Two> .

Then a request to /data/* will return a serialization of the RDF graph merge of the datasets contained in resource1.ttl and resource2.ttl:

GET /data/* HTTP/1.1
Host: example.org
HTTP/1.1 200 OK
<>
    a <http://www.w3.org/ns/ldp#BasicContainer> ;
    <http://www.w3.org/ns/ldp#contains> <resource1.ttl>, <resource2.ttl> .

<resource1.ttl>
    a <https://example.org/ns/type#One> .

<resource2.ttl>
    a <https://example.org/ns/type#Two> .

Alternative: using SPARQL

Another possible way of reading and writing data is to use SPARQL. Currently, our Solid servers support a subset of SPARQL 1.1, where each resource is its own SPARQL endpoint, accepting basic SELECT, INSERT and DELETE statements.

To read (query) a resource, the client can send a SPARQL SELECT through a form-encoded HTTP GET request. The server will use the given resource as the default graph that is being queried. The resource can be an RDF document or even a container. The response will be serialized using application/json mime type.

For instance, the client can send the following form-encoded query SELECT * WHERE { ?s ?p ?o . }:

REQUEST:

GET /data/?query=SELECT%20*%20WHERE%20%7B%20%3Fs%20%3Fp%20%3Fo%20.%20%7D HTTP/1.1
Host: example.org

RESPONSE:

HTTP/1.1 200 OK
{
  "head": {
    "vars": [ "s", "p", "o" ]
  },
  "results": {
    "ordered" : false,
    "distinct" : false,
    "bindings" : [
      {
        "s" : { "type": "uri", "value": "https://example.org/data/" },
        "p" : { "type": "uri", "value": "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" },
        "o" : { "type": "uri", "value": "http://www.w3.org/ns/ldp#BasicContainer" }
      },
      {
        "s" : { "type": "uri", "value": "https://example.org/data/" },
        "p" : { "type": "uri", "value": "http://purl.org/dc/terms/title" },
        "o" : { "type": "literal", "value": "Basic container" }
      }
    ]
  }
}

Creating content

When creating new resources (directories or documents) using LDP, the client must indicate the type for the new resource that is going to be created. LDP uses Link headers with specific URI values, which in turn can be dereferenced to obtain additional information about each type of resource. Currently, our LDP implementation supports only Basic Containers.

LDP also offers a mechanism through which clients can provide a preferred name for the new resource through a header called Slug.

Creating containers (directories)

To create a new basic container resource, the Link header value must be set to the following value: Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"

For example, to create a basic container called data under https://example.org/, the client will need to send the following POST request, with the Content-Type header set to text/turtle:

REQUEST:

POST / HTTP/1.1
Host: example.org
Content-Type: text/turtle
Link: <http://www.w3.org/ns/ldp#BasicContainer>; rel="type"
Slug: data
<> <http://purl.org/dc/terms/title> "Basic container" .

RESPONSE:

HTTP/1.1 201 Created

Deleting containers

A container can only be deleted if it contains no resources.

Creating documents (files)

To create a new resource, the Link header value must be set to the following value: Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"

For example, to create a resource called test under https://example.org/data/, the client will need to send the following POST request, with the Content-Type header set to text/turtle:

REQUEST:

POST / HTTP/1.1
Host: example.org
Content-Type: text/turtle
Link: <http://www.w3.org/ns/ldp#Resource>; rel="type"
Slug: test
<> <http://purl.org/dc/terms/title> "This is a test file" .

RESPONSE:

HTTP/1.1 201 Created

More examples can be found in the LDP Primer document.

HTTP PUT to create

An alternative (though not standard) way of creating new resources is to use HTTP PUT. Although HTTP PUT is commonly used to overwrite resources, this way is usually preferred when creating new non-RDF resources (i.e. using a mime type different than text/turtle).

REQUEST:

PUT /picture.jpg HTTP/1.1
Host: example.org
Content-Type: image/jpeg
...

RESPONSE :

HTTP/1.1 201 Created

Another useful Solid feature that is not yet part of the LDP spec deals with using HTTP PUT to recursively create new resources. This feature is really useful when the client wants to make sure it has absolute control over the URI namespace -- e.g. migrating from one personal data store to another. Although this feature is defined in HTTP1.1 RFC2616, we decided to improve it slightly by having servers create the full path to the resource (including intermediate containers), if it didn't exist before. (If you're familiar with the Unix command line, think of it as mkdir -p.) For instance, a calendar app uses a URI pattern (structure) based on dates when storing new events (i.e. yyyy/mm/dd). Instead of performing several POST requests to create a month and a day container when switching to a new month, it could send the following request to create a new event resource called event1:

REQUEST:

PUT /2015/05/01/event1 HTTP/1.1
Host: example.org

RESPONSE:

HTTP/1.1 201 Created

This request would then create a new resource called event1, as well as the missing intermediate resources -- containers for the month 05 and the day 01 under the parent container /2015/.

To avoid accidental overwrites, Solid servers must support ETag checking through the use of If-Match or If-None-Match HTTP headers.

IMPORTANT: Using PUT to create standalone containers is not supported, because the behavior of PUT (overwrite) is not well defined for containers. You MUST use POST (as defined by LDP) to create containers alone.

Alternative: Using SPARQL

To write data, clients can send an HTTP PATCH request with a SPARQL payload to the resource in question. If the resource doesn't exist, it should be created through an LDP POST or through a PUT.

For instance, to update the title of the container from the previous example, the client would have to send a DELETE statement, followed by an INSERT statement. Multiple statements (delimited by a ;) can be sent in the same PATCH request.

REQUEST:

PATCH /data/ HTTP/1.1
Host: example.org
Content-Type: application/sparql-update
DELETE DATA { <> <http://purl.org/dc/terms/title> "Basic container" };
INSERT DATA { <> <http://purl.org/dc/terms/title> "My data container" }

RESPONSE:

HTTP/1.1 200 OK

IMPORTANT: There is currently no support for blank nodes and RDF lists in our SPARQL patches.

Discovering server capabilities - the OPTIONS method

Returns a list of headers describing the server's capabilities.

REQUEST:

OPTIONS /data/ HTTP/1.1
Host: example.org

RESPONSE:

HTTP/1.1 200 OK
Accept-Patch: application/json, application/sparql-update
Accept-Post: text/turtle, application/ld+json
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: OPTIONS, HEAD, GET, PATCH, POST, PUT, DELETE
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: User, Triples, Location, Link, Vary, Last-Modified, Content-Length
Allow: OPTIONS, HEAD, GET, PATCH, POST, PUT, DELETE

WAC-Allow headers

Servers SHOULD send a WAC-Allow response header on HEAD and GET, with a value like:

WAC-Allow: user="read write append control",public="read"

In general, the format is user=" + user-permissions = ",public=" + public-permissions + ". User-permissions and public-permissions should both be space-separated lists, containing a subset of ['read', 'write', 'append', 'control']. If 'write' is present then 'append' should also be present.