Anzeige
Anzeige
Ratgeber
Artikel merken

RESTful API und Plugins im Praxiseinsatz für den Datenexport: Ein Eventkalender mit Ruby on Rails

Die Website wevent.org basiert auf Ruby on Rails und ist ein Eventkalender, in dem Nutzer Veranstaltungen eintragen, Freunde einladen und sich über Events in der Nähe informieren. Um eine Schnittstelle für externe Anwendungen wie Desktop-Kalender oder Feedreader zu bieten, wurde eine RESTful API realisiert, über die verschiedene Datenformate angefordert werden können. Für denselben Zweck kommen auch zwei Plugins zum Einsatz.

7 Min. Lesezeit
Anzeige
Anzeige

Wer seine Anwendung RESTful entwickelt (siehe auch T3N Nr. 7 und 8) bietet eine uniforme Schnittstelle [1], über die die eigenen Daten (Resourcen) anderen Anwendungen zur Verfügung gestellt werden. Bei einem webbasierten Eventplaner bietet es sich dabei an, dass die Nutzer ihren Veranstaltungskalender auch offline auf dem Desktop nutzen oder sich per RSS über neu eingetragene Events informieren lassen können.

Anzeige
Anzeige

Die Ausgabe der Daten für das Frontend in Form einer HTML-Datei ist oftmals bereits in einer „Action“ implementiert, es muss also lediglich auf das vom Client angeforderte Format reagiert werden. Kalenderapplikationen fragen in der Regel das Standardformat iCal (meine_events.ics) an, für Feedreader wiederum kann eine Repräsentation als RSS oder Atom angeboten werden. Wem das noch nicht reicht, der stellt für weitere Anwendungen, wie zum Beispiel Web Services, auch noch XML, YAML oder JSON zu Verfügung – dank Rails ist das alles mit wenigen Zeilen Code möglich.

respond_to whatever

Mit dem Befehl „respond_to“ lässt sich auf den vom Client gesendeten Accept-Header oder das explizit angeforderte Datenformat reagieren. Erhält Rails beispielsweise eine Anfrage, deren HTTP-Header „Accept: application/xml“ enthält oder mit der auf
„http://wevent.org/events.xml“ zugegriffen wird, so rendert die Action „index“ eine Liste aller Events als XML. Folgende Einstellungen sind dafür nötig:

Anzeige
Anzeige
RUBY ON RAILS
class EventsController < ApplicationController
	def index
		@page_title = „Alle Events“
		@events = Event.find(:all)
		respond_to do |format|
			 format.html
			 format.xml   { render_xml_for  @events }
			 format.json  { render_json_for @events }
			 format.yaml { render_yaml_for @events }
			 format.rss    { render_rss_for  @events, :title => @page_title }
			 format.atom { render_atom_for @events, :title => @page_title }
			 format.ics    { render_ical_for @events, :title => @page_title }
		end
	end
end

Listing 1

Innerhalb des respond_to-Blocks werden die möglichen Ausgabeformate aufgelistet – die Reihenfolge spielt dabei keine Rolle, da der Client die Reihenfolge der gewünschten Formate im Accept-Header festlegt oder das Format durch die Dateiendung explizit angegeben wurde.

Anzeige
Anzeige

Wer schon einmal eine XML-Ausgabe seiner Modelldaten in eine Anwendung implementiert hat, dem wird auffallen, dass die im Listing gezeigte Implementation nicht zu den Rails-Bordmitteln gehört. Standardmäßig würde die XML-Ausgabe mit folgendem Befehl realisiert:

RUBY ON RAILS
format.xml  { render :xml => @events.to_xml }

Listing 2

Um einen einheitlichen Aufruf der render-Methoden zu erzielen, werden sie als Methoden des ApplicationControllers (Listing folgt später) implementiert. Das Vorgehen ist auch deshalb sinnvoll, um anschließend den Aufruf des RSS-, Atom- und iCal-Renderings zu wrappen. Das wird aus dem Folgenden ersichtlich.

Anzeige
Anzeige

RSS- und Atom-Export in zehn Minuten

Der Rails 1.2 Core bringt kein RSS- oder Atom-Rendering von Objekten wie beispielsweise „@events.to_rss“ mit sich. Solche Anforderungen lassen sich aber Rails-typisch mit einem Plugin lösen: Der Resource Feeder [2] macht es einem recht leicht, RSS- und Atom-Feeds aus Modelldaten zu generieren. Zunächst müssen dafür die beiden Plugins „Simply Helpful“ und der darauf basierende „Resource Feeder“ installiert werden:

SHELL
$ script/plugin install simply_helpful
$ script/plugin install resource_feeder

Listing 3

Für die Implementation der Ausgabe in den verschiedenen Formaten stellt das letztgenannte Plugin im Controller die beiden Methoden „render_rss_feed_for“ und „render_atom_feed_for“ zur Verfügung, die zwei Parameter entgegennehmen:

  1. Ein Array mit Objekten, zu denen jeweils ein Item im Feed erzeugt werden soll (in unserem Fall ein Eintrag pro Event).
  2. Optional: Ein Hash mit Optionen, der unter anderem das Mapping der Objektattribute auf die Feeditem-Elemente angibt.
RUBY ON RAILS
options[:feed][:title]		     # Titel des Feeds
options[:feed][:link]               # Link zum Feed
options[:feed][:description]  # Beschreibung des Feeds
options[:feed][:language]     # Sprache, default: "en-us"
options[:feed][:ttl]                # Time to live, Minuten die das Feed gecacht werden kann, default: 40
options[:item][:title]             # Methode, die den Titel des Items zurückgibt
options[:item][:description] # Methode, die den Inhalt des Items in plain text zurückgibt
options[:item][:content_encoded] # Optional, encodierter Inhalt (mit HTML o.ä.)
options[:item][:pub_date]    # Methode, die das Datum des Eintrags zurückgibt, default: created_at
options[:url_writer]              # Optional, eigener UrlWriter, nützlich bei verschachtelten Resourcen

Listing 4

Die auf die Items bezogenen Optionen geben jeweils den Namen der Objektmethode an, die das Veröffentlichungsdatum, den Titel oder die Beschreibung zurückgeben. Im Idealfall können die Angaben entfallen. Vorraussetzung dafür ist, dass das Modell schon über die richtigen Attribute (z. B. „created_at“, „title“, „description“) verfügt – ansonsten muss, wie im folgenden Listing zu sehen, noch etwas nachkonfiguriert werden. Da die meisten Optionen durch die Anwendung hindurch gleich bleiben (bspw. „Language“ und „Time to live“), werden die Methoden zum Rendern der Formate gewrapped, um Wiederholungen in den einzelnen Aufrufen zu vermeiden [3]. Das Listing enthält auch schon das Rendern des Formats iCalendar, dessen Export dann im nächsten Abschnitt implementiert wird:

Anzeige
Anzeige
RUBY ON RAILS
class ApplicationController < ActionController::Base
	protected
		def render_xml_for(objects, options = {})
			render :xml => objects.to_xml(options)
		end
		def render_json_for(objects)
			render :json => objects.to_json
		end
		def render_atom_for(objects, options = {})
			render_atom_feed_for objects, { 
				:feed => { :title => options[:title] },
				:item => {
					     # Die Methode summary des Eventobjekts gibt den Titel zurück,
					     # description_for_feed die Beschreibung, welche im Feed auftauchen soll 
				      :title => :summary, 
					     :description => :description_for_feed } }
		end
		def render_rss_for(objects,options = {})
			render_atom_feed_for objects, { 
				:feed => { :title => options[:title], :language => "de-DE", :ttl => 60 },
				:item => { 
				      :title => :summary, 
				      :description => :description_for_feed, 
				      :content_encoded => :content_encoded } }
		end
		def render_ical_for(objects, options = {})
			ical = Icalendar::Calendar.new # Erstellen eines neuen Kalenderobjekts
			# Einstellungen für den Kalender
			ical.product_id = "-//wevent.org//iCal 1.0//DE"
			ical.custom_property("X-WR-CALNAME;VALUE=TEXT", "wevent.org: #{options[:title]}")
			ical.custom_property("X-WR-TIMEZONE;VALUE=TEXT", "Europe/Berlin")
			# Eventobjekte als iCalendar-Daten rendern und dem Kalender hinzufügen
			ical.add(objects.to_ical)
			render_without_layout :text => ical.to_ical # Ausgabe der fertigen iCalendar-Datei
		end
    end
end

Listing 5

Export von Daten als iCalendar

iCalendar ist ein Standardformat zum Austausch von Kalenderdaten, das von allen verbreiteten Kalenderapplikationen unterstützt wird. Der Export des Formats mit der Dateiendung „.ics“ gehört zwar nicht zu den Rails-Bordmitteln, die Library „iCalender“, die sich als Ruby Gem installieren lässt, schafft aber Abhilfe.

SHELL
$ sudo gem install icalendar

Listing 6

Die Library ermöglicht das Erstellen eines Kalenderobjekts, das zunächst mit den Daten der enthaltenen Veranstaltungen befüllt werden muss. Dazu wird die Methode „to_ical“ in unserem Eventmodell, das ein Eventobjekt im iCalendar-Format zurückgibt, implementiert:

RUBY ON RAILS
require 'icalendar' # Einbinden der iCalendar-Library
class Event < ActiveRecord::Base
	def to_ical
		ical_event = Icalendar::Event.new # Erstellen des Eventobjekts im iCalendar-Format
		# Befüllen des Veranstaltungseintrags
		ical_event.summary = summary        # Titel der Veranstaltung
		ical_event.description = description   # Beschreibung der Veranstaltung
		ical_event.dtstamp = created_at.iso8601     # Zeitstemplel des Eintrags im ISO-Format
		ical_event.dtstart = datetime_start.iso8601  # Zeitstempel des Beginns
		ical_event.dtend =  datetime_end.iso8601   # Zeitstempel des Endes
		ical_event.uid = „wevent:event=#{id}“ # Eindeutige ID des Events
		ical_event.location = "#{venue_name}, #{city_name}" # Veranstaltungsort
		ical_event.to_ical # gibt das iCal Objekt zurück
	end
end

Listing 7

Die beschriebene Methode kann nun im Controller genutzt werden, um ein Array mit Eventobjekten als kompletten Kalender auszugeben: Der Aufruf von „to_ical“ auf einem Array sorgt dafür, dass durch das Array iteriert und auf jedem Element die Methode „to_ical“ ausgeführt wird. Ihr Rückgabewert (der Kalendereintrag des einzelnen Events) wird anschließend dem Kalender hinzugefügt („ical.add(objects.to_ical“), der schließlich gerendert wird.

Anzeige
Anzeige

Optimierungsmöglichkeiten

Der Einfachheit halber wurden in diesem Tutorial immer alle Events aus der Datenbank geladen, um sie anschließend auszuge-ben. Das macht in der Praxis aus mehreren Gründen wenig Sinn. Zum einen wäre die Last auf der Datenbank enorm groß, wenn bei jedem Aufruf der API alle Daten geladen würden, und zum anderen erzeugt solch eine große Datenmenge auch beim Client zu viel Last, da die Daten vor der Verarbeitung geparst werden müssen.

Über die RESTful API von wevent können Entwickler die Daten auch für andere Anwendungen nutzen.

Über die RESTful API von wevent können Entwickler die Daten auch für andere Anwendungen nutzen.

Das Problem kann ebenso, wie auch in anderen Fällen für die Weboberfläche sinnvoll, umgangen werden:
Durch Partitionierung/Paginierung der Daten. So erhält der Client bei jedem Aufruf nur eine Untermenge der Daten (beispielsweise 15 Events). Nach Abarbeitung der Daten kann er durch die Übergabe eines Parameters den nächsten Teil der Daten anfordern (zum Beispiel über http://wevent.org/events.xml?page=2).

In der aktuellen Rails-Version 1.2 ist Pagination noch enthalten, mit Rails 2.0 wird das Konzept allerdings auf Plugins ausgelagert. Daher empfiehlt es sich, rechtzeitig nach einer Plugin-Lösung für das Problem Ausschau zu halten – als Empfehlung kann an dieser Stelle das Plugin „will_paginate“ [4] genannt werden, das sich momentan als präferierte Lösung unter Rails-Entwicklern abzeichnet.

Anzeige
Anzeige

Fazit

Wie das Tutorial zeigt, erlaubt es Ruby on Rails, Anwendungen nach außen zu öffnen, um so weitere Nutzungsmöglichkeiten der Daten für die Nutzer zur Verfügung zu stellen. Ganz allgemein werden APIs in Zukunft eine immer größere Rolle spielen und besonders die Verbreitung von REST-Schnittstellen wird zunehmen. Ruby on Rails hat das Konzept REST bereits fest integriert und wird auch dadurch weiter an Bedeutung gewinnen.

Mehr zu diesem Thema
Fast fertig!

Bitte klicke auf den Link in der Bestätigungsmail, um deine Anmeldung abzuschließen.

Du willst noch weitere Infos zum Newsletter? Jetzt mehr erfahren

Anzeige
Anzeige
Schreib den ersten Kommentar!
Bitte beachte unsere Community-Richtlinien

Wir freuen uns über kontroverse Diskussionen, die gerne auch mal hitzig geführt werden dürfen. Beleidigende, grob anstößige, rassistische und strafrechtlich relevante Äußerungen und Beiträge tolerieren wir nicht. Bitte achte darauf, dass du keine Texte veröffentlichst, für die du keine ausdrückliche Erlaubnis des Urhebers hast. Ebenfalls nicht erlaubt ist der Missbrauch der Webangebote unter t3n.de als Werbeplattform. Die Nennung von Produktnamen, Herstellern, Dienstleistern und Websites ist nur dann zulässig, wenn damit nicht vorrangig der Zweck der Werbung verfolgt wird. Wir behalten uns vor, Beiträge, die diese Regeln verletzen, zu löschen und Accounts zeitweilig oder auf Dauer zu sperren.

Trotz all dieser notwendigen Regeln: Diskutiere kontrovers, sage anderen deine Meinung, trage mit weiterführenden Informationen zum Wissensaustausch bei, aber bleibe dabei fair und respektiere die Meinung anderer. Wir wünschen Dir viel Spaß mit den Webangeboten von t3n und freuen uns auf spannende Beiträge.

Dein t3n-Team

Melde dich mit deinem t3n Account an oder fülle die unteren Felder aus.

Bitte schalte deinen Adblocker für t3n.de aus!
Hallo und herzlich willkommen bei t3n!

Bitte schalte deinen Adblocker für t3n.de aus, um diesen Artikel zu lesen.

Wir sind ein unabhängiger Publisher mit einem Team von mehr als 75 fantastischen Menschen, aber ohne riesigen Konzern im Rücken. Banner und ähnliche Werbemittel sind für unsere Finanzierung sehr wichtig.

Schon jetzt und im Namen der gesamten t3n-Crew: vielen Dank für deine Unterstützung! 🙌

Deine t3n-Crew

Anleitung zur Deaktivierung
Artikel merken

Bitte melde dich an, um diesen Artikel in deiner persönlichen Merkliste auf t3n zu speichern.

Jetzt registrieren und merken

Du hast schon einen t3n-Account? Hier anmelden

oder
Auf Mastodon teilen

Gib die URL deiner Mastodon-Instanz ein, um den Artikel zu teilen.

Anzeige
Anzeige