schule:rest_in_15_minuten
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende ÜberarbeitungLetzte ÜberarbeitungBeide Seiten der Revision | ||
schule:rest_in_15_minuten [2016-01-22 22:04] – [Weitere Links] programmable web marco.bakera | schule:rest_in_15_minuten [2017-04-19 08:39] – Externe Bearbeitung 127.0.0.1 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
+ | ====== REST in 15 Minuten ====== | ||
+ | |||
+ | Bei [[wpde> | ||
+ | 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, | ||
+ | testen. Dafür habe ich das Webframework [[http:// | ||
+ | verwendet. | ||
+ | |||
+ | 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:// | ||
+ | # 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('/ | ||
+ | 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(' | ||
+ | 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 += "< | ||
+ | for k in zitate: | ||
+ | html += "< | ||
+ | html += "< | ||
+ | html += "</ | ||
+ | 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('/ | ||
+ | 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 " | ||
+ | | ||
+ | # 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('/ | ||
+ | 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(" | ||
+ | response.status = 201 # 201: Created | ||
+ | |||
+ | # Als Ergebnis geben wir die komplette URI des neuen Zitates zurück | ||
+ | return request.url + "/" | ||
+ | | ||
+ | # 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, | ||
+ | </ | ||
+ | |||
+ | ===== Aufruf des Webservices ===== | ||
+ | |||
+ | Nun können wir testweise auf den Web-Service zugreifen. Ich benutze hierfür das | ||
+ | Kommandozeilentool [[wpde> | ||
+ | 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: | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | 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 " | ||
+ | {} | ||
+ | </ | ||
+ | |||
+ | 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: | ||
+ | http:// | ||
+ | </ | ||
+ | |||
+ | 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." | ||
+ | http:// | ||
+ | |||
+ | $ curl -d "foo bar" localhost: | ||
+ | http:// | ||
+ | </ | ||
+ | |||
+ | Das Ergebnis können wir uns erneut ausgeben lassen. | ||
+ | |||
+ | <code bash> | ||
+ | $ curl -H " | ||
+ | |||
+ | {" | ||
+ | "foo bar"} | ||
+ | </ | ||
+ | |||
+ | ===== 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> | ||
+ | |||
+ | <code javascript> | ||
+ | var http = require(' | ||
+ | |||
+ | // Erstelle den Server. Der Parameter ist eine | ||
+ | // Callback-Methode, | ||
+ | var server = http.createServer( | ||
+ | function (req, res) { | ||
+ | res.write(' | ||
+ | res.write(" | ||
+ | res.write(" | ||
+ | res.write(' | ||
+ | res.end(); | ||
+ | }); | ||
+ | |||
+ | |||
+ | server.listen(12345); | ||
+ | </ | ||
+ | |||
+ | Bei einem Aufruf der URL ''< | ||
+ | |||
+ | Request erhalten. | ||
+ | Method: GET | ||
+ | URL: /hallo | ||
+ | Hallo Client | ||
+ | ===== Weitere Links ===== | ||
+ | * [[http:// | ||
+ | * [[http:// | ||
+ | * [[http:// | ||
+ | * [[http:// | ||
+ | * [[https:// | ||
+ | * [[wpde> | ||
+ | * [[http:// | ||
+ | * [[Webserver programmieren]] | ||
+ | * [[https:// | ||
+ | * [[http:// | ||
+ | |||
schule/rest_in_15_minuten.txt · Zuletzt geändert: 2017-04-19 10:27 von marco.bakera