Benutzer-Werkzeuge

Webseiten-Werkzeuge


schule:rest_in_15_minuten

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
schule:rest_in_15_minuten [2015-09-12 17:53] – [Weitere Links] +couchdb marco.bakeraschule:rest_in_15_minuten [2017-04-19 10:27] (aktuell) – [REST in 15 Minuten] added hug marco.bakera
Zeile 1: Zeile 1:
 +====== REST in 15 Minuten ======
 +
 +Bei [[wpde>Representational State Transfer|REST]] basierten
 +Anwendungen handelt es sich um einfache Versionen von Webservices. REST
 +steht für REpresentational State Transfer. Dahinter verbergen sich verschiedene Regeln, 
 +die sich stark an etablierte Konzepte von HTTP
 +anlehnen. Da es eine sehr lose und einfache Spezifikation ist, kann sie jeder
 +einfach umsetzen und, weil sich die Spezifikation stark an HTTP
 +anlehnt, ist die Umsetzung mit vielen unterschiedlichen Programmiersprachen
 +möglich. Ich habe mich entschieden, das ganze einmal in [[Python]] zu
 +testen. Dafür habe ich das Webframework [[http://bottlepy.org/|Bottle]]
 +verwendet. Eine weitere und einfachere Möglichkeit bietet das Paket [[http://hug.rest/|hug]].
 +
 +Ein zentrales Element in REST und auch HTTP sind die Ressourcen, die über eine
 +URI bzw. URL erreichbar sind. Das können
 +Datenbankobjekte oder Dienste sein. Bei der Umsetzung von REST mit HTTP werden
 +die unterschiedlichen Methoden von HTTP genutzt: GET zum Abrufen
 +und POST zum Speichern und Erstellen von Daten. Wie das Ergebnis
 +aussehen soll, kann zusätzlich in den Headerinformationen des HTTP requests eingetragen
 +werden.
 +
 +===== Quelltext des Webservices =====
 +
 +Als Beispiel habe ich eine kleine Zitatesammlung gewählt, die aus einer Liste von Zitaten besteht.
 +Es können neue Zitate hinzugefügt und die bestehenden Zitate angezeigt werden.
 +Schauen wir uns den Quelltext etwas genauer an. Ich habe ihn in der Datei rest.py abgelegt.
 +
 +<file python rest.py>
 +# coding=UTF8
 +# ^^^^^^^^^^^ 
 +# Mit der ersten Zeile legen wir die Kodierung der Quelltextdatei fest. Dies
 +# ist nötig, damit wir hier auch deutsche Umlaute benutzen können.
 +  
 +# Die Anwendung wurde mit dem Bottle-Framework (http://bottlepy.org/)
 +# erstellt. Dies ist ein einfaches Webframework für Python Anwendungen. Wir
 +# importieren zunächst die notwendigen Methoden.
 +from bottle import route, run, debug, request, response
 +  
 +# In dem Dictionary zitate sollen Zitate gesammelt werden. Jedes Zitat ist
 +# über eine ID erreichbar: {0: "Zitat 1", 1 : "Zitat 2", ...}
 +zitate = {}
 +  
 +# Mit route wird eine Ressource festgelegt. Dies ist der Teil, der hinter der
 +# Adresse des Hostnamens folgt. Eine Anfrage wird normalerweise über ein
 +# GET-request entgegen genommen. In diesem Fall wird eine Liste aller Zitate
 +# ausgegeben. Es ist guter Stil, den Namen des Ressource jeweils im Plural zu
 +# verwenden.
 +@route('/zitate', method='GET')
 +def zitate_liste():
 +    # Über den Header können wir prüfen, welche Form der Ausgabe der Client
 +    # erwartet. Da wir bei REST nur von Repräsentationen ausgehen, können die
 +    # Inhalte unterschiedlich dargestellt und damit auch angefordert
 +    # werden. Wir unterstützen HTML und Json als Formate.
 +    if request.get_header('Accept') == "application/json":
 +        return zitate
 +    else:
 +        # Wenn kein besonderes Format angefordert wurde, wird HTML
 +        # ausgegeben. Wir stecken die Zitate in eine Tabelle und geben diese
 +        # zurück.
 +        html = "<html><body><h1>Zitate</h1><table border='1'>"
 +        html += "<tr><td>Id</td><td>Zitat</td></tr>"
 +        for k  in zitate:
 +            html += "<tr>"            
 +            html += "<td>" + str(k) + "</td><td>" + zitate[k] + "</td>"
 +            html += "</tr>"
 +        html += "</table></body></html>"
 +        return html
 +  
 +# Ein bestimmtes Zitat kann über seine Nummer angesprochen und einzeln
 +# ausgegeben werden. Der Parameter <nr> in der URL wird an die Methode
 +# übergeben.
 +@route('/zitate/<nr>')
 +def zitate_get(nr):
 +    zid = int(nr)
 +    if zid in zitate:
 +        return zitate[zid]
 +    else:
 +        # Die Nummer und damit das Zitat wurden nicht gefunden.
 +        # Über den Statuscode melden wir den Misserfolg an den Client. 
 +        # Status 404: Not Found
 +        response.status = 404
 +        return "Zitatnummer nicht vorhanden: " + nr
 +  
 +# Damit wir etwas für die Anzeige haben, müssen auch neue Zitate eingetragen
 +# werden können. Diese geschieht über die HTTP Post-Methode. Die Daten, also
 +# der Text des Zitates, wird über den Body des requests übertragen. In der
 +# Antwort wird der Client über die Adresse der neuen Ressource
 +# informiert. Zusätzlich setzen wir die neue Adresse im Headerfeld Location.
 +# Schließlich wird der Status der Antwort auf 201 (Created) gesetzt. Damit die
 +# Methode nur auf POST reagiert, wird die route entsprechend konfiguriert.
 +@route('/zitate', method='POST')
 +def zitat_erstellen():
 +    # Die ID für das nächste Zitat wird bestimmt. Wenn es noch keine Zitate
 +    # gibt, ist es die 0, ansonsten wird die größte ID um 1 erhöht.
 +    if len(zitate) == 0:
 +        neue_id = 0
 +    else:
 +        neue_id = max(zitate.keys()) + 1
 +
 +    zitate[neue_id] = request.body.readline()
 +    response.set_header("Location", request.url + "/" + str(neue_id))
 +    response.status = 201 # 201: Created
 +
 +    # Als Ergebnis geben wir die komplette URI des neuen Zitates zurück
 +    return request.url + "/" + str(neue_id)
 +      
 +# Anmerkung: Komplexe Einträge wie z.B. ein Zitat mit Informationen über den
 +# Autor und das Jahr der Verwendung werden nicht als Text, sondern als Json-
 +# oder XML-Inhalt übermittelt. Es sind aber auch binäre Daten wie Bilder oder
 +# MP3-Dateien möglich.
 +  
 +
 +# START des Webservers auf Port 8000.
 +#
 +  
 +debug(True)
 +run(port=8000, reloader=True)  
 +</file>
 +
 +===== Aufruf des Webservices =====
 +
 +Nun können wir testweise auf den Web-Service zugreifen. Ich benutze hierfür das
 +Kommandozeilentool [[wpde>cURL]], da es viele Freiheiten bei der Erstellung des
 +requests und dem Auslesen der Antwort bietet. Zunächst rufen wir die Adresse
 +einfach nur auf. Mit der Option -i werden die Headerinformationen zusätzlich
 +angezeigt.
 +
 +<code bash>
 +$ curl localhost:8000/zitate;
 +<html><body><h1>Zitate</h1><table border='1'><tr><td>Id</td><td>Zitat</td></tr></table></body></html>
 +</code>
 +
 +Ohne weitere Angaben wird HTML als Ausgabeformat produziert. Dies könnte ein
 +Browser sogar anzeigen. Da wir noch keine Zitate hinzugefügt haben, zeigt die
 +Ausgabe eine leere Tabelle.
 +
 +Probieren wir es nun mit einer anderen Variante und fordern Json als
 +Ausgabeformat an. Die URI ist die gleiche, denn es ist ja die gleiche
 +Ressource, auf die ich zugreifen möchte. Lediglich die Darstellung soll eine
 +andere sein. Daher müssen wir ein Headerfeld entsprechend konfigurieren. Mit
 +der Option -H können wir dies tun.
 +
 +<code bash>
 +$ curl -H "Accept:application/json" localhost:8000/zitate;
 +{}
 +</code>
 +
 +Nun wird Json als Rückgabeformat verwendet. Im Moment ist unser Ergebnis
 +noch eine leere Zitatesammlung.
 +
 +Wir können aber nicht nur Daten ausgeben lassen, sondern auch setzen oder
 +erstellen. Dazu muss eine HTTP POST Methode aufgerufen werden. Wir nehmen
 +diesmal die gleiche Ressource - also URI - und generieren eine POST Anfrage
 +mit -d. Dieser Parameter erwartet noch Daten, die wird senden wollen. Wir
 +geben hier nur den Text eines  Zitates an.
 +
 +<code bash>
 +$ curl -d "The cake is a lie." localhost:8000/zitate;
 +http://localhost:8000/zitate/0
 +</code>
 +
 +Als Ergebnis erhalten wir eine URL mit dem neu erstellten Zitat. Fügen wir
 +noch ein paar Zitate hinzu.
 +
 +<code bash>
 +$ curl -d "Go To Statement Considered Harmful." localhost:8000/zitate; 
 +http://localhost:8000/zitate/1
 +
 +$ curl -d "foo bar" localhost:8000/zitate;
 +http://localhost:8000/zitate/2
 +</code>
 +
 +Das Ergebnis können wir uns erneut ausgeben lassen.
 +
 +<code bash>
 +$ curl -H "Accept:application/json" localhost:8000/zitate
 +
 +{"0": "The cake is a lie.", "1": "Go To Statement Considered Harmful.", "2":
 +"foo bar"}
 +</code>
 +
 +===== Wie geht's weiter? =====
 +
 +Das obige Beispiel ist ein erster Einstieg in REST. Das Programm kann um verschiedene Aspekte erweitert werden. Greif dir doch einen Aspekt heraus und probiere es einmal selbst.
 +
 +  * Ein Zitat kann mittels der HTTP-Methode DELETE gelöscht werden. 
 +  * Informationen über Zitate werden angereichert um z.B. den Autor.
 +  * Für verändernde Operationen wie das Anlegen eines neuen Zitates muss man sich mit Nutzerdaten anmelden.
 +
 +===== Server mit nodejs =====
 +
 +Mit [[wpde>node.js]] kann ein HTTP-Server in JavaScript einfach mit Hilfe des [[https://nodejs.org/api/http.html|http-Paketes]] erstellt werden. Der folgende Quelltext zeigt das Prinzip.
 +
 +<code javascript>
 +var http = require('http');
 +
 +// Erstelle den Server. Der Parameter ist eine 
 +// Callback-Methode, die bei einem Request aufgerufen wird.
 +var server = http.createServer(
 + function (req, res) {
 + res.write('Request erhalten.\n');
 + res.write("Method: " + req.method + "\n");
 + res.write("URL: " + req.url + "\n");
 + res.write('Hallo Client');
 + res.end();
 + });
 +
 +
 +server.listen(12345);
 +</code>
 +
 +Bei einem Aufruf der URL ''<nowiki>http://localhost:12345/hallo</nowiki>'' wird im Browser anschließend folgende Ausgabe angezeigt.
 +
 +  Request erhalten.
 +  Method: GET
 +  URL: /hallo
 +  Hallo Client
 +===== Weitere Links =====
 +  * [[http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm|Kapitel 5]] der Dissertation "Architectural Styles and the Design of Network-based Software Architectures" von Roy Thomas Fielding (der "Erfinder" von REST)
 +  * [[http://www.ibm.com/developerworks/webservices/library/ws-restful/|RESTful Web services: The basics]] - guter Übersichtsartikel
 +  * [[http://www.ietf.org/rfc/rfc2616.txt|RFC zu HTTP/1.1]] - vollständige Beschreibung der HTTP-Standards, inklusive Beschreibung aller HTTP Methoden und Haderinformationen.
 +  * [[http://www.restapitutorial.com/|REST API Tutorial]] liefert auf einer übersichtlichen Seite die wesentlichen Informationen.
 +  * [[https://couchdb.apache.org/|CouchDB]] ist eine nicht-relationale Datenbank, die mit HTTP-Methoden (GET, POST, PUT, etc.) bedient werden kann. Die Inhalte werden in JSON-Dokumenten abgelegt und können über URLs abgerufen werden.
 +  * [[wpde>Microservices]] stellen eine Funktionalität bereit und lassen sich mit sprachunabhängigen Programmierschnittstellen miteinander verbinden.
 +  * [[http://www.programmableweb.com/|ProgrammableWeb]] stellt Schnittstellen unterschiedlicher WebServices vor.
 +  * [[Webserver programmieren]]
 +  * [[https://github.com/jkbrzt/httpie|httpie]] ist eine Weiterentwicklung cURL.
 +  * [[http://www.hug.rest/|hug]] ist eine Python-Bibliothek, mit deren Hilfe Methoden als WebService zur Verfügung gestellt werden können.
 +