Recently, we stumbled upon Inrupt’s Solid and after going through their fundamental documentation, we became keen on building a sample solid application and get a better understanding of it. All of Solid’s examples are built on JQuery and NodeJS. We like Python and so we wanted to build some Python-based examples. This post will focus on how to use Python to load, parse and traverse Solid data.
Before going into deep details, lets first understand what Solid is about and what kind of data it deals with.
Solid Overview
Solid (derived from “social linked data”) is a decentralized platform for social Web applications. In the Solid platform, each user stores their data in personal online datastore (or pod) served by different public pod servers and identity providers. In solid, the applications and data are decoupled. Applications built using Solid platform do not have their own data but they can access data which is stored in a place of user’s choice using different protocols, authentication and access control system.
Before going into details of our code, we will first understand about few most commonly used terms in Solid which we will be referring in below sections like POD, WebID, Linked data, Namespaces and RDF(Resource Description framework) which is the data model for Linked Data.
POD(Personal online datastore)
In Solid platform, each user stores their data in a personal online datastore (pod) that resides on a pod server. You can give applications read/write access to parts of your data in POD. You can learn more about Solid POD’s here
WebID
Solid uses WebID URIs as universal usernames. When you register with Solid, you get a public Solid POD URL(which is like the homepage for your Solid pod) and public Solid WebID which acts as a global ID that you can use to identify and authenticate yourself with other PODs across the world. In Solid, the registered identity provider stores the user’s profile document in Turtle and RDF formats. You can learn more about WebID here
Linked Data
In Solid platform, users can store any piece of the data in their pods and this data in one pod can be linked with data in different pods. This connected data is referred to as Linked Data. You can learn more about Linked Data here
Namespaces in RDF
RDFLib provides several short-cuts to working with many URIs in the same namespace. The purpose of the namespace is simply to avoid name conflicts with tags of the same name. You can refer here for more details on RDF Vocabulary and namespaces
RDF – the data model for Linked Data
Linked Data is typically represented in RDF, the Resource Description Framework. It is based on the idea of making statements about resources in expressions of the form subject–predicate–object, known as triples. RDF has different syntaxes like Turtle, N-Triples, N3, JSON-LD, RDF/XML etc., You can learn more about RDF here
Sample Python solid profile viewer application
Based on the example profile viewer app, we built a sample python solid application using flask. This profile viewer will show data from different people’s profiles based on the given WebID. We used python rdflib library for reading Solid data.
Pre-requisites: In order to read and write Solid data, we need our own Solid POD and identity. We created a POD from Get a Solid POD
To brief, our sample solid python web application does the following:
1. Gets the user input ‘Profile’ webID using the HTTP Get method.
2. Creates an RDF Graph
3. Based on the webID, reads data from a Solid pod.
4. Parse the data returned into a graph
5. Get the friends list for the given webID
6. Display the returned friends webID list on the browser.
To get started, we need to download and install some Python modules. While there are several Python modules for working with RDF data, this post will focus on RDFLib. The RDFLib module provides a powerful set of tools for creating, parsing, traversing and editing RDF data. It allows us to interact with Linked Data stored in Solid pods.
RDFLib aims to be a pythonic RDF API, a Graph is a python collection of RDF Subject, Predicate, Object Triples:
Let’s dive into the code. We created a file named ‘sample_python_solid.py‘ with following content:
""" This is a Flask application for Inrupt Solid profile viewer. """ from flask import Flask, jsonify, render_template, request import json import logging import urllib2 import rdflib from rdflib import URIRef,Graph,RDF from rdflib.namespace import FOAF app = Flask(__name__) def post_friends_list(uri): "create,parse graph and get the friends list for the given URI" # Create a Empty graph graph = rdflib.Graph() graph.parse(uri) for person in graph[: RDF.type: FOAF.Person]: name = graph.value(person, FOAF.name) friends = list(graph[person:FOAF.knows]) app.logger.info('%s friends', friends) if friends: app.logger.info("%s's friends:", graph.value(person, FOAF.name)) return friends,name @app.route("/", methods=['GET','POST']) @app.route("/view", methods=['GET','POST']) def view(): "Endpoint for getting the friends list for the given URI" if request.method == 'GET': #return the form return render_template('sample_solid.html') if request.method == 'POST': #return the answer uri = request.form.get('profile') result,name = post_friends_list(uri) api_response = {"answer": result, "name": name} return jsonify(api_response) #---START OF SCRIPT if __name__ == '__main__': app.run(host='127.0.0.1', port=6464, debug= True) |
First, we make a Flask object, use the ‘route’ decorator functions to define GET (Render a template when the route is triggered with GET method) and POST (post URI to that URL). Then, call post_friends_list() function(which we will be discussing in below section) and finally a ‘run’ function when we run it locally (which you can confirm by calling python sample_python_solid.py and visiting localhost:6464 in your browser.)
Using built-in RDFLib functions
In the above code, you can see a method called post_friends_list(), which is the actual python code in which we used RDFLib libraries to create a RDF Graph. A Graph is a python collection of RDF Subject, Predicate, Object Triples. It is like a database which is arbitrary in terms of what is related to what. The way you parse RDF with rdflib is you create a Graph, which is a sort of empty holder for data. Imagine this as a big container for data, and you can throw into the container as much data as you like, then just filter out the bits you want.
First we should import the Graph class from the rdflib package and create a Graph instance as shown below:
from rdflib import URIRef, Graph graph = rdflib.Graph() |
The ‘graph’ variable now has an empty graph. Now we should load some data into the graph. The graph object has a method called ‘parse’ which allows you to give it a file name from your local system or an HTTP URI and it will try to load data from that source. In our case, we’ll load in data to parse a specified URI which the user inputs in the URL.
To fetch user’s profile document, we are iterating over the triples and getting the name of the person using FOAF(Friend of a Friend) Vocabulary. Below are the steps performed:
1. Loop over each FOAF: Person in the graph(RDF.type: FOAF.Person)
2. Using graph.value() to get the person’s name
3. Fetch the list of friends using graph[person:FOAF.knows] attribute.
4. Return the user full name and his friend’s webID list.
About our HTML page
We have a input field which accepts the webID from the user. When clicked on the View button the user information(Full Name and friend’s list) is loaded in the browser page. We have written Javascript code to make the friend’s webID clickable. When a webID link is clicked from the friend’s list, that person’s webID is loaded into the Profile input field and when the user clicks on the View Button, the name of his friends is loaded in the page. This information is fetched directly from the friend’s pods. Note:- You need to add a few friends to your profile before trying this.
You can find the code associated with this post on Qxf2’s GitHub. We hope this article helps you get started with implementing Solid web applications using python.
References
1. Solid – Getting Started
2. RDFLib Documentation
3. Making sense of linked data with python
I am an experienced engineer who has worked with top IT firms in India, gaining valuable expertise in software development and testing. My journey in QA began at Dell, where I focused on the manufacturing domain. This experience provided me with a strong foundation in quality assurance practices and processes.
I joined Qxf2 in 2016, where I continued to refine my skills, enhancing my proficiency in Python. I also expanded my skill set to include JavaScript, gaining hands-on experience and even build frameworks from scratch using TestCafe. Throughout my journey at Qxf2, I have had the opportunity to work on diverse technologies and platforms which includes working on powerful data validation framework like Great Expectations, AI tools like Whisper AI, and developed expertise in various web scraping techniques. I recently started exploring Rust. I enjoy working with variety of tools and sharing my experiences through blogging.
My interests are vegetable gardening using organic methods, listening to music and reading books.
Hello Indira, thanks for your post! Did you made any progress with this Pods technology?
Hi Gilbert,
In recent times, we have not got a chance to work on Pods technology.
Regards,
Rohini