Documentation, backgrounders and tutorial material related to information design, engineering, semantics, ontologies, and vocabularies
→ Standards and namespaces
→ Controlled vocabularies
→ Semantic Web Tools
→ Learning resources
A tutorial to introduce LD APIs using pyldapi.
In this tutorial, we will learn to:
Attendees will:
We will use the /example-code/pyldapi
directory as a starting point and a template for an implementation of a
pyLDAPI service.
See presentation slides for overview of the Pet LD API.
The recommended layout of a pyLDAPI implementation is using the Model-View-Controller pattern and creating directories to suit. See below:
/
-- model/
-- pet.py
-- view/
-- static/
...
-- templates/
...
page_pet.html
-- controller/
-- classes.py
-- pages.py
-- app.py
-- _config.py
...
Let’s run the example pyLDAPI. If you haven’t run the code yet, run the following
$ virtualenv venv
$ source venv/bin/activate
# Or on a windows bash client
$ source venv/Scripts/activate
$ pip install -r requirements.txt
$ export FLASK_APP=app.py
$ export FLASK_ENV=development
$ flask run --port=3000 --host=0.0.0.0
Let’s look at the Pets register at http://localhost:3000/pets/
.
We can see the pets listed in the register. The Pet Register functionality is defined in the code base in the following file:
/controller/classes.py
(just glance at it - we’ll look at it in more detail later).
Let’s click on one of the Pets - Rex, and take a look at the view of a Pet instance.
We can see a basic landing page for the Pet Rex.
The information used to populat the Pet instance view comes from:
/controller/classes.py
/model/pet.py
The Jinja template is used to render the view of the information for Rex. THis is located at:
/view/templates/page_pet.html
Take a closer look at these files and draw a map of how the files are connected to render the Pet view.
/controller/classes.py
/model/pet.py
/view/templates/page_pet.html
Now let’s add a new pet.
Which file and where in the file would we add the required information?
What do you notice about the information model?
Based on the template that exists, develop some code to add a new Pet view.
We have covered how the Pet section of the Example pyLDAPI works using a very basic (JSON) dataset and how to extend it for different LD Views.
In this next part of the tutorial, we will work on adding a new Register - a Pizza register. We will reuse definitions from DBPedia and expose them as Linked Data resources.
Go to https://dbpedia.org/sparql and put in the SPARQL query text shown below in the Query editor. This will query all Pizza types and their label.
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dbo: <http://dbpedia.org/ontology/>
select distinct ?p ?label
where {
?p dbo:type <http://dbpedia.org/resource/Pizza> .
?p rdfs:label ?label .
FILTER(LANG(?label) = "" || LANGMATCHES(LANG(?label), "en"))
} LIMIT 100
We can use this query as the basis for the Pizza Register we will now implement.
To implement the Pizza Register, we need to:
from SPARQLWrapper import SPARQLWrapper, JSON
@classes.route('/pizza/')
def pizza():
"""
The Register of Pizzas
:return: HTTP Response
"""
# prepare items for the ContainerRenderer response instance
no_of_items = 0
try:
page = request.values.get('page') if request.values.get('page') is not None else 1
per_page = request.values.get('per_page') if request.values.get('per_page') is not None else 20
items = _get_pizza_items(page, per_page)
no_of_items = len(items)
except Exception as e:
print(e)
return Response('The Pizza Register is offline', mimetype='text/plain', status=500)
# create the ContainerRenderer response instance
r = pyldapi.ContainerRenderer(
request,
request.url,
'Pizza Register',
'A register of Pizza',
"http://example.org/def/Pizza",
"Pizza",
items,
no_of_items
)
return r.render()
pyLDAPI provides the Register function via ContainerRenderer
. ContainerRenderer
expects these inputs:
We will now implement the _get_pizza_items()
function from the above and using the .
The SPARQL Endpoint is located at http://dbpedia.org/sparql.
The SPARQLWrapper library is used to issue the remote queries in python.
def _get_pizza_items(page, per_page):
sparql = SPARQLWrapper("http://dbpedia.org/sparql")
sparql.setQuery("""
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dbo: <http://dbpedia.org/ontology/>
select distinct ?p ?label
where {
?p dbo:type <http://dbpedia.org/resource/Pizza> .
?p rdfs:label ?label .
FILTER(LANG(?label) = "" || LANGMATCHES(LANG(?label), "en"))
} LIMIT 100
""")
sparql.setReturnFormat(JSON)
results = sparql.query().convert()
arr_items = []
for result in results["results"]["bindings"]:
label = result["label"]["value"]
uri = result["p"]["value"]
tokens = uri.split("http://dbpedia.org/resource/")
pizza_name = tokens[1]
# Format array of items the way pyldapi requires
arr_items.append( ("{}pizza/{}".format(request.url_root, pizza_name), label, "pizza") )
return arr_items
pyldapi expects the array of items in the register to have a particular structure. It requires (URI, URI, label) or (URI, label).
You should now have a working pizza registry at http://localhost:3000/pizza/
We now want to enable users to be able to view each Pizza and some details, as well as content negotiate by media type.
DBPedia has a specific way of providing RDF content via the URL template (text/turtle):
http://dbpedia.org/data/{Name of the Resource}.ttl
We want to load this into our environment and render the information in a tailored way.
We will create 2 new files - the PizzaRenderer
class in the /model/pizza.py
file and a Jinja view template file in /view/templates/page_pizza.html
/
-- model/
-- pizza.py
-- view/
-- templates/
page_pizza.html
Add the following code in the pizza-model.txt file in /model/pizza.py
.
from model.pizza import PizzaRenderer
from rdflib import Graph
@classes.route('/pizza/<string:pizza_name>')
def pizza_instance(pizza_name):
instance = None
pizza_ttl_url = "http://dbpedia.org/data/{}.ttl".format(pizza_name)
print(pizza_ttl_url)
#get the Turtle format for the pizza
r = requests.get(pizza_ttl_url)
print(r.status_code)
print(r.text)
rdf_data = r.text
#load into RDFLib
g = Graph()
g.parse(data=rdf_data, format="turtle")
instance = {"graph" : g}
if instance is None:
return Response("Not Found", status=404)
renderer = PizzaRenderer(request, request.base_url, instance, 'page_pizza.html')
return renderer.render()
Create a file called /view/templates/page_pizza.html
with the following lines in the pizza-1.txt file in this link.
Add the code in the pizza-model2.txt file in /model/pizza.py
.
Modify the __init__
function to add these lines to call the above function in /model/pizza.py
:
self.instance['_data'] = {}
self._populate_instance_from_rdf()
Add the following code in the pizza-2.txt file in this link
We have covered how the Pet section of the Example pyLDAPI works using a very basic (JSON) dataset and how to extend it for different LD Views.
We also showed how we can take some existing RDF resources and create a Pizza LD API - Pizza register, Pizza model and views. We showed how to pull in different data content into the views.