Schlagwort-Archive: Content-Negotiation

Linked Data Social Network

Ich beschäftige mich nicht nur theoretisch mit den Themen Linked Data und dezentralen sozialen Netzwerken, sondern arbeite derzeit auch ganz konkret an einer Social Network Plattform auf Basis von Linked Data. Dass was ich seit gestern online habe, würde ich aber nicht mal als Pre-Alpha bezeichnen, also erwartet nicht zu viel, falls ihr auf den gleich folgenden Link klickt.

Mein Projekt „Desone“ (Decentralized Social Network) hat derzeit auch noch wenig mit „Networking“ zu tun. Es ist eher ein Profil-Hoster und derzeit auch nur für mein eigenes Profil (Anmeldung ist noch nicht möglich, klickt so oft auf Login wie ihr wollt). Editierfunktionen bietet es auch noch nicht (nichtmal für mich selbst). Kommt aber alles noch!

Zum „Network“ wird das ganze aber dann doch wieder, weil Desone natürlich Linked Data bereitstellt. In meiner Bekanntenliste verlinke ich auf meine Kontakte bei identi.ca (StatusNet stellt praktischerweise FOAF bereit) und Twitter (semantictweet.com machts möglich) sowie auf einige wenige Personen die selbst ein FOAF-Profil hosten.

Meine Interessen verlinken zudem auf die DBpedia und mein Wohnort auf geonames.org. Wie ihr seht, sind dank Linked Data also schon sehr viele Angaben möglich, ohne das Desone selbst diese Informationen (z.B. Orte, Interessen) hosten muss. Desone hostet nur das Profil, den Rest stellt praktischerweise das Web of Data bereit.

Genug der langen Rede, schauts euch an, wenn ihr mögt: http://me.desone.org/person/aveltens#me

An die RDF-Daten kommt ihr dank Grails Content-Negotiation auf folgenden Wegen:

Ich werde euch natürlich über das Projekt auf dem Laufenden halten.

Content-Negotiation mit Grails

Content-Negotiation, zu Deutsch Inhaltsvereinbarung, ermöglicht es dem Webserver unterschiedliche Repräsentationen einer Resource an den Client auszuliefern und ist damit eine wichtige Funktion im Web of Data. Nehmen wir zum Beispiel an, die folgende URI identifiziert die Stadt Berlin:

http://example.com/city/berlin

Web-Browser fordern für gewöhnlich HTML-Dokumente an und sollen daher beim Abruf dieser URI eine schön aufbereitete Webseite mit Informationen über Berlin und ggf. ein paar Bilder ausgeliefert bekommen. Gleichzeitig sollen jedoch auch RDF-Daten über Berlin im Web of Data verfügbar gemacht werden.

In bin ein großer Freund des Grails Web-Frameworks, welches ich sowohl beruflich als auch privat nutze. Mit Grails wird – neben so ziemlich allem was Web-Entwicklung angeht – auch die Content-Negotiation zum Kinderspiel. Ich möchte das an dem bereits angesprochenen Beispiel praktisch verdeutlichen. (Ich gebe allerdings keine Einführung in Grails selbst, dazu verweise ich auf die hervorragende Dokumentation)

Nehmen wir an es gibt eine Domainklasse City, welche in verschiedenen Repräsentationen durch den CityController ausgeliefert werden soll.

Wir legen folgendes Mapping in UrlMappings.groovy an:

static mappings = {
  "/city/$name"(resource: "city")
}

Dadurch werden die Requests an URLs der Form /city/name RESTful gemappt und an den CityController weitergeleitet. D.h. GET-Requests gehen automatisch an die show-Action des Controllers POST an save u.s.w. (Details siehe Grails-Dokumentation). Außerdem wird der Part hinter /city/ als Parameter „name“ in die Action hineingegeben.

Mithilfe des withFormat-Ausdrucks kann der Controller auf verschiedene Anfrageformate unterschiedlich reagieren:

class CityController {
  def rdfRenderer

  def show = {
    def city = City.findByName(params.name)
    withFormat {
      html { return [cityInstance: city] }
      json { render city as JSON }
      rdf { rdfRenderer.render(city) }
    }
  }
}

Der rdfRenderer ist ein fiktives Beispiel. Sowas wird leider nicht von Grails mitgeliefert. RDF lässt sich aber sehr leicht mit groovyrdf generieren. Die Codeblöcke werden bei Anfragen nach den entsprechenden Formaten ausgeführt. html und json liefert Grails von Haus aus mit, was rdf bedeutet muss man jedoch kurz selbst in der Config.groovy bekannt geben:

grails.mime.types = [
  html: ['text/html','application/xhtml+xml'], // bereits vorkonfiguriert
  json: ['application/json','text/json'], // bereits vorkonfiguriert
  // [...]
  rdf: 'application/rdf+xml' // selbst ergänzt
]

Das wars im Prinzip schon, leider gibts in Grails derzeit noch einen kleinen Bug: Grails liest für die Content-Negotiation nicht wie üblich den HTTP-Accept-Header aus, sondern den Content-Type. Der Content-Type gibt eigentlich das Format der Daten an, welche man hinsendet und nicht der Daten welche man anfordert. Das lässt sich aber leicht über eine einfache Konfiguration beheben. Dazu in der Config.groovy folgende Einstellung setzen:

grails.mime.use.accept.header = true

Das wars auch schon! Abhängig vom gesetzten Accept-Header reagiert unser Controller nun anders auf den Request und kann entsprechend eine GSP rendern um eine HTML-Seite auszuliefern, JSON-Daten ausgeben oder aber RDF! Und sogar folgende URIs sind gültig:

http://example.com/city/berlin.html - Liefert immer die HTML-Seite
http://example.com/city/berlin.json - Liefert immer JSON-Daten
http://example.com/city/berlin.rdf - Liefert immer RDF-Daten

Wir haben also mit http://example.com/city/berlin eine eindeutige URI, welche die Resource Berlin identifiziert und zum anfragenden Client passende Daten ausliefert. Zudem haben wir für jede der Repräsentationen eine URI mit der entsprechenden „Dateiendung“. Das ist genau das, was wir im Web of Data brauchen 🙂