-
Notifications
You must be signed in to change notification settings - Fork 15
Introduction to Content Negotiation
In this site and many others we tend to refer to things like http://example.org/thing as URI (Uniform Resource Identifier) instead of URL (Uniform Resource Locator). The different is in its purpose: To name a thing is different to know how to reach it. For example, in a certain context, the string Alvaro's car
define unequivocally a thing (my car) but it doesn't make it clear how to access or reach it. A more general identifier could be the serial number of my laptop: this number is unique in the world, so when I use it, it should be clear for everybody that I'm talking about a specific laptop. Again, this doesn't give us any information how to reach or access that laptop.
However on the traditional web, identifier and location are the same: I can name my webpage as http://example.org/index.html
and I can also retrieve it using the same string. When things can be identified and accessed by the same identifier on the Web using the HTTP protocol, we call them Information Resources.
I can however give an identifier to other things besides webpages and images: For example, my car can be http://graves.cl/mycar
while I can identify myself using http://alvaro.graves.cl
. Since you cannot retrieve or access my car or myself using HTTP, we call them Non-information Resouces
RDF in general and Linked Data in particular are aimed to describe information about lots of things that are not necessarily information resources, from US States to people. However, it is not possible to access states or people through the HTTP protocol, what can we do about it?
The de facto standard to do this is to use content negotiation (conneg) which is a mechanism to obtain a suitable representation of a resource, based on what the client will accept.
Thus, if a client requests http://example.org/myCar
which is not an information resource, LODSpeaKr will return an HTTP code 303 (See Other) which will redirect to a document with information related to http://example.org/myCar
. Depending on the Accept
header sent by the client, LODSPeaKr will try to server the best possible representation (RDF/XML, Turtle, N-Triples or HTML+RDFa). A diagram can be seen in Figure 1.
Services are information resources by definition (their URI doesn't identify an entity from the triple store, but they deliver documents that can be transmitted via HTTP). Thus, when requesting a particular representation for a service, LODSPeaKr will NOT do a 303 redirection, but it will simply deliver the content using the best representation possible.
$ curl -H 'Accept: application/rdf+xml' -i http://foo.com/classes
Date: Sat, 10 Mar 2012 17:09:37 GMT
Server: Apache/2.2.20 (Ubuntu)
Accept-Ranges: bytes
X-Powered-By: PHP/5.3.6-13ubuntu3.6
Transfer-Encoding: chunked
Content-Type: application/rdf+xml
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="http://data.semanticweb.org/conference/iswc/2010/break-2010-11-09T10-00-00">
<rdf:type rdf:resource="http://data.semanticweb.org/ns/swc/ontology#BreakEvent"/>
</rdf:Description>
<rdf:Description rdf:about="http://data.semanticweb.org/conference/iswc/2011/break-2011-10-24T12:30:00">
<rdf:type rdf:resource="http://data.semanticweb.org/ns/swc/ontology#BreakEvent"/>
</rdf:Description>
...
It is possible to obtain a particular representation despite what the client's Accept
header by adding an extension to the service name. This is particularly useful when we want to obtain JSON representation in the browser (despite the fact that application/json
is not usually part of the Accept
string in a modern browser)
$ curl -H 'Accept: application/rdf+xml' -i http://foo.com/classes.ttl
HTTP/1.1 200 OK
Date: Sat, 10 Mar 2012 17:11:46 GMT
Server: Apache/2.2.20 (Ubuntu)
Accept-Ranges: bytes
X-Powered-By: PHP/5.3.6-13ubuntu3.6
Transfer-Encoding: chunked
Content-Type: text/n3
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ns0: <http://data.semanticweb.org/ns/swc/ontology#> .
<http://data.semanticweb.org/conference/iswc/2010/break-2010-11-09T10-00-00> rdf:type ns0:BreakEvent .
<http://data.semanticweb.org/conference/iswc/2011/break-2011-10-24T12:30:00> rdf:type ns0:BreakEvent .
<http://data.semanticweb.org/conference/iswc/2010/break-2010-11-11T15-30-00> rdf:type ns0:BreakEvent .
Suppose we want to create an API that delivers bibtex files based on Linked Data. Thus, we have information about meetings, people, etc.
First, we need to tell LODSPeaKr that we want to serve data in a new content type. In settings.inc.php
we add the following line:
$conf['http_accept']['bib'] = array('application/x-bibtex');
In this way, we are telling LODSPeaKr how it must accept that particular content type.
We have a service where queries/main.query
retrieves the relevant information and html.template
displays it in HTML form. We than add a new template, called bib.template
, that will serve all the content types related to bib
(right now is only application/x-bibtex
but it could be multiple content types)
componens/services/papers/
|
|-> html.template
|
|-> bib.template
|
|-> queries/
|
|->main.query
In bib.template
we will create a template that matches the Bibtext format. We will add values using Haanga as we usually do in the html case (lets assume query contains values such as paperId
, author
, title
, etc)
{%for i in models.main%}
@article{ {{i.paperId.value}},
author = "{{i.author.value}}",
title = "{{i.title.value}}",
journal = "{{i.journal.value}}",
year = {{i.year.value}},
}
{%endfor%}
We can later request $ curl -H 'Accept: application/x-bibtex' -i http://foo.com/papers
to obtain the bibtex file. Since browsers usually don't request application/x-bibtex
, we can force to obtain that content simply by pointing it to http://foo.com/papers.bib
.
We can also request application/x-bibtex
to single URIs. We just need to create a new bib.template
for the types and uris previously defined.