Hi, I am Lauro Vanderborght and this is episode six of Digita’s Solid Tech Talks. In the previous episodes, we described how Solid pods are a combination of vault and database, and how we can interact with the resources within that database using the HTTP protocol. Now, it’s time to explain how you actually read from and write to a pod.
We already mentioned that the Solid ecosystem efficiently combines existing standards. The protocol for how to read from and write to a pod is based on the Linked Data Platform standard, or LDP. LDP defines a set of rules for HTTP operations to read and write web resources. These web resources can be digital files, or data structured in RDF: the ideal, mathematical way to describe resources. So, LDP provides the foundation for a Solid pod being both a file vault and a database.
All web resources in a pod that can be read from and written to are identified with a URL. Dereferencing file resources returns the file itself, but dereferencing RDF resources returns structured data about the resource itself, which typically links to other resources, both within and outside the pod. A specific type of RDF resources are called auxiliary resources: these auxiliary resources are tagged as they solely exist to provide additional info about other resources within the Solid pod. They can be used for example to describe the access control policies.
All resources within a pod -- so file resources ánd RDF resources -- can be organized: they can be contained. In what? Exactly: containers. Containers are a specific type of RDF resources, meaning that a container can contain resources which are files, data, and also other containers: you can create a nested structure of containers. Root level containers are called storages. So, the complete hierarchy within a pod can be described using one or more storages, each containing one or more containers and resources, and each container again containing one or more nested containers and resources.
Containers are specific types of RDF resources. In RDF resources, you can put any structured data you want. This is typically data that describes the resource itself, but that’s not obliged. In containers, you can also put any structured data that you want, but additionally, containers contain the containment links that only the pod itself can manage. The pod makes sure that all contained resources are linked from the container using these containment links, and that these links stay up to date when resources are created or destroyed.
There is a 1 to 1 correspondence between this hierarchy of containers and the URL path names of the resources. For example, following resource has as path “level 1, level 2”. A conforming Solid pod has to make sure that the parent containers “level 1” and “level 1, level 2” exist. As a result of this rule, you as a user can be sure you cannot create orphan resources: each resource within your pod is contained within one specific container.
Using these containment links and this 1 to 1 correspondence makes sure that all resources are discoverable by following the links between the different containers. Following links to discover resources is called the ‘follow-your-nose’ principle. It is one of the basic principles within the Solid ecosystem to make sure data is automatically discoverable by both users and applications. So by using this LDP protocol, an application can automatically discover how any Solid pod is structured, and it can derive how to work with the pod.
Now it’s time to deep dive into the inner workings of how to read and write resources. The Solid pod API is a RESTful API, which implies that a request uses standard HTTP methods and uses HTTP request headers to provide additional information. Finally, a request can have a body: the actual contents of the request. The response contains -- besides the actual response to the request -- an HTTP status code clarifying whether an operation was successful or not, and HTTP response headers providing additional information. Generally speaking, you can do three actions involving resources: you can read resources, write resources, and destroy resources. Of course, you as a user or application can only do these actions if you are allowed to do them, but this is part of another video.
You typically read resources using a GET request on the resource’s URL. A successful response is the resource itself with a 200 status code. In the response headers, you might get additional information, for example, if you are allowed to also write to that resource. RDF resources can easily be returned in different representations using content negotiation, depending on the needs of the application. For this, you could use an HTTP Accept header in your request, specifying you prefer to get the resource as JSON for example.
You could also use the HEAD or OPTIONS methods on the resource’s URL. A HEAD request only returns the metadata about the resource (for example, whether the resource exists or not), and an OPTIONS request only returns the metadata about what you can do with the resource (for example, whether you can write to the resource or not). A GET request returns all this metadata including the resource itself. HEAD and OPTIONS can be useful when you are working with very large data, you do not necessarily want to download the entire resource just to know whether a resource exists or not.
How do you know if a resource does not exist? Well, you will get a response with a 404 status code instead of 200. When you don’t have access to a resource, you will get a 401 response.
To write to a resource, you use POST, PUT, or PATCH requests. By using HTTP headers you can specify if you want to create a container. If not a container, the Solid pod makes sure to create the container if it didn’t exist yet, and creates the right containment links. POST and PUT requests both create resources, with one difference. With a POST request, you specify ‘create a resource, but the Solid pod can create an identifier automatically’, whereas with a PUT request, you specify ‘create a resource with this specific identifier’. In a POST or PUT request you put the entire resource in the body of the request. A PATCH request can be used to update a part of an RDF resource, so this only works on already existing URLs. You can have different ways of specifying how the body of a PATCH request looks like, but right now, a simple version of a SPARQL update query is used, basically stating ‘remove these pieces of structured data and add these pieces of structured data’.
And finally, you can destroy existing resources using the DELETE request.
So to summarize, let’s go through a typically reading and writing scenario of an application.
- Your application connects with a Solid pod. By dereferencing its URL, it can retrieve the information of what storages are available in that pod.
- You create a new container with a specific identifier using a PUT request
- You create a new resource without identifier using a POST request
- If you haven’t already, you can read that new resource using a GET request, because the previous response returned which identifier was created. You could also use the follow-your-nose principle to discover the contained resources from your created container.
- You can update that resource using either PUT (when you want to rewrite the resource) or PATCH (when you want to update a part of the resource)
- Finally, you destroy a resource using DELETE. When a container is empty, you can also destroy that container.
This is how you read from and write to a pod! In the next videos, we’ll talk about how we can make this process secure. See you soon.