1. Protokolle und Standards

Dieser Text bietet einen sehr kompakten Überblick über die Protokolle, die du kennen solltest, wenn du aktiv Webanwendungen entwickeln möchtest. Die Informationen in diesem Kapitel sind grob in folgende Abschnitte unterteilt:

1.1 Standardisierung mit RFCs

Wenn du dich mit Protokollen und konkreten Implementierungen technischer Verfahren rund um das Internet beschäftigst, wirst du immer wieder mit RFCs (Request for Comments) konfrontiert. Die RFCs dienen als öffentliches Diskussionsforum für technische und organisatorische Fragen des Internets. Sie wurden mit dem ARPA-NET im Jahre 1969 ins Leben gerufen. Die RFC 0001 wurde am 7. April 1969 veröffentlicht, noch während der laufenden Entwicklung des ARPANET.

RFCs werden fortlaufend nummeriert und können verschiedene Stufen durchlaufen. Es gibt keine Versionsnummern. Wird ein RFC umfassend weiterentwickelt, erscheint ein neues Dokument mit einer neuen Nummer. Das alte wird als obsolet gekennzeichnet. Werden aus RFCs Standards verabschiedet, so erscheinen diese in einer zweiten Dokumentform, die durch STD gekennzeichnet ist. Der Zusammenhang zwischen RFCs und STDs ist in RFC 2500 geregelt. Der Standardisierungsprozess wird in RFC 2026 erläutert.

Als gute Informationsquelle für RFCs ist die folgende Webseite zu empfehlen:

Hier kannst du in der RFC- und STD-Datenbank komfortabel stöbern. Wenn du nach tiefergehenden Informationen zu bestimmten Protokollen wie beispielsweise ICMP oder DNS suchst, trage diese in die Suchmaske ein.

Abbildung: Eine gute Informationsquelle ist der RFC-Editor
Abbildung: Eine gute Informationsquelle ist der RFC-Editor

1.2 Das OSI-Referenzmodell

Für die Entwicklung und Bewertung von Kommunikationsprozessen wird in der IT-Welt häufig zum ISO/OSI-Referenzmodell Bezug genommen. Dieses Modell wurde im Jahre 1984 von der ISO (International Organization for Standardization) verabschiedet und beschreibt alle wesentlichen Prozesse bei der IT-gestützten Datenübertragung über ein Schichtenmodell. Komplett ausgeschrieben steht die Abkürzung ISO/OSI übrigens für Reference Model for Open Systems Interconnection of the International Organization for Standardization.

Die folgende Tabelle zeigt die sieben Schichten des ISO/OSI-Referenz-modells und ihre Bedeutungen.

Tabelle: Schichten des ISO/OSI-Referenzmodells
Nr. Bezeichnung Aufgabe bzw. Beispielanwendungen
7 Anwendung Nutzerschnittstelle Programmschnittstelle
6 Darstellung Kodierung und Dekodierung
5 Sitzung Kommunikationssteuerung  
4 Transport Aufbau von Verbindungen Datentransport
3 Vermittlung Adressierung und Routing von Datenpaketen
2 Sicherung, Logical Link Control Kontrollfunktionen, Datenfragmentierung
  MAC (Media Access Control)  
1 Bitübertragung Physikalischer Netzwerktransport (Kabel, Funk etc.)

Bei einem genau nach diesem Modell entwickelten Übertragungsverfahren arbeitet auf jeder Ebene genau eine Komponente beziehungsweise ein Netzwerkprotokoll. Zwischen zwei Computersystemen werden dann jeweils alle Schichten durchlaufen. Der eigentliche Datenaustausch findet schließlich nur über die Schicht 1, beispielsweise über das Netzwerkkabel, statt. Die einzelnen Schichten innerhalb eines Partners “kommunizieren” damit jeweils nur mit den direkt darüber und darunter liegenden Nachbarn über die Protokolle und technischen Komponenten. Dadurch sind die höheren Schichten unabhängig von den Prozessen, die sich weiter unten abspielen. Ob die Schicht 1 technisch über ein Kupfer- oder ein Glasfaserkabel implementiert ist, ist für die Protokollschicht, die kontrolliert Datenpakete versenden will, irrelevant.

Das ISO/OSI-Referenzmodell ist ein wenig theoretisch und wird in der Praxis selten konsequent umgesetzt. Das beste Beispiel dafür sind die am meisten verbreiteten Netzwerkprotokolle TCP und IP. Die Entwicklung dieser Protokolle ist älter als das Referenzmodell, sodass sich die sogenannte Internet-Protokollfamilie nur teilweise darin abbilden lässt. Die Motivation für die Entwicklung einer eigenständigen Standardisierungsschicht war die notwendige Vereinfachung und damit Verringerung des Implementierungsaufwands.

1.3 Die Internet-Protokollfamilie

Die Internet-Protokollfamilie (Internet Protocol Suite, IPS) kann in vier Schichten eingeteilt werden, die ähnlich wie die des Referenzmodells strukturiert sind. Ab Schicht 2 übernehmen verschiedene Protokolle jeweils spezifische Aufgaben. Einige werden in den nächsten Abschnitten noch näher vorgestellt.

Abbildung: Internet-Protokollfamilie im Vergleich zum ISO/OSI-Referenzmodell
Abbildung: Internet-Protokollfamilie im Vergleich zum ISO/OSI-Referenzmodell

Nachfolgend werden die wichtigsten Protokolle der IPS vorgestellt. Die Reihenfolge entspricht dabei der im IPS-4-Schichtenmodell (siehe Abbildung).

Etwas speziell ist das ARP-Protokoll (Adressauflösung). Es ist zwar rein technisch über dem DLCMAC (Ethernet) angeordnet, gehört aber nicht zu Schicht 3. Es wird deshalb manchmal auch als Schicht 2,5-Protokoll bezeichnet. Hieran kann man die Schwächen solcher Modelle erkennen, die nicht immer die komplexe Realität perfekt abbilden.

1.3.1 Address Resolution Protocol (ARP)

Über dieses Protokoll, welches auf einer sehr elementaren Ebene arbeitet, erfolgt die Zuordnung von IP-Adressen zu den physischen MAC-Adressen der Netzwerkadapter der beteiligten Kommunikationsteilnehmer. MAC steht für Media Access Control. MAC-Adressen sind normalerweise eindeutig, sodass eine Verwechslung von Teilnehmern an dieser Stelle ausgeschlossen werden kann. Allerdings gibt es Netzwerkadapter, die das Eingeben einer benutzerdefinierten MAC-Adresse zulassen. Ebenso lassen sich in virtualisierten Umgebungen die MAC-Adressen manipulieren, um bestimmten Netzwerkanforderungen zu genügen.

Die Informationen zu den MAC-Adressen der beteiligten Netzwerkcomputer werden bei Windows (Server), wie bei anderen Betriebssystemen auch, in einem ARP-Cache gehalten. Damit müssen diese nicht immer wieder neu ermittelt werden. Den ARP-Cache kannst du über die Eingabeaufforderung mit dem Kommando arp (Linux und Windows nutzen dasselbe Kommando) und der Option –a anzeigen lassen:

$ arp -a

Hast du mehrere Netzwerkadapter in deinem Computersystem installiert, kannst du den ARP-Cache für einen bestimmten Adapter abfragen, indem du dessen IP-Adresse angibst:

$ arp –a 192.168.100.6

Welche und wie lange Daten in diesem Cache gehalten werden, kann man anpassen. Dies ist in der Praxis allerdings kaum notwendig. Eine genaue Syntaxbeschreibung zum Programm arp findest du auf Wikipedia.

1.3.2 Internet Control Messaging Protocol (ICMP)

Dieses Protokoll dient vor allem zum Transport von Diagnose-, Kontroll- und Routingdatenpaketen im Netzwerk. Es befindet sich wie das Internet Protocol (IP) auf Schicht 2 des IPS-Schichtenmodells. ICMP wird beispielsweise vom Dienstprogramm ping benutzt, um Informationen von einem Host zu erfragen.

Abbildung: Ping auf einen Server (Windows-Kommandozeile)
Abbildung: Ping auf einen Server (Windows-Kommandozeile)

1.3.3 Internet Protocol (IP)

IP dient zum eigentlichen Transport der Nutzdaten im Netzwerk. Das Protokoll zeichnet sich durch folgende Merkmale aus:

Da IP zu den wichtigeren Protokollen im Web gehört, soll an dieser Stelle etwas genauer auf die Zusammensetzung des Kopfes (Headers) eingegangen werden.

Abbildung: IP-Header
Abbildung: IP-Header
Abbildung: IP-Fragmentierung
Abbildung: IP-Fragmentierung

IPv6 vs IPv4

Das IP Protokoll in der Version 6 bereits seit Langem spezifiziert. Trotzdem steht hier IPv4 im Vordergrund. Für dich als Entwickler hat IPv6 kaum eine Relevanz, da lokale Netzwerke, Testumgebungen, Build-Maschinen usw. fast immer über Adresseübersetzungen (NAT) in lokalen IPv4-Umgebungen laufen. IPv6-Themen sind eher für Administratoren und Netzwerktechniker wichtig. Technisch hat sich IPv6 bislang nur im Smart Home-Bereich etabliert, wo das Netzwerk durch die Komponenten automatisch konfiguriert wird.

1.3.4 Transmission Control Protocol (TCP)

TCP ist eine Schicht über IP angesiedelt und verfügt gegenüber diesem über einen wirksamen Mechanismus zur Fehlerkorrektur. Neben einer Nummerierung der Datenpakete werden Prüfsummen generiert, mit deren Hilfe die Integrität der Daten sichergestellt wird. Wird ein Fehler erkannt, erfolgt automatisch eine Anforderung des bzw. der defekten Datenpakete, das Gleiche gilt für den Fall, dass ein Paket bis zum Ablauf einer bestimmten Zeit nicht eingetroffen ist. Auch diese Daten werden neu angefordert.

Da jede Leitung unterschiedliche qualitative Eigenschaften hat, kann TCP die Parameter, wann ein Paket zu wiederholen ist, dynamisch anpassen. Auf diese Weise wird immer eine optimale Performance garantiert.

Abbildung: TCP-Header
Abbildung: TCP-Header
1.3.4.1 Port

Zusätzlich zu den IP-Quell- und Zieladressen verwendet TCP sogenannte Portnummern. Diese ergeben zusammen mit den IP-Adressen eine eindeutige Verbindung. Jeder Dienst bekommt einen Port zugewiesen, auf dem dieser eingehende Verbindungen entgegennimmt. Da viele Standarddienste immer die gleichen Ports verwenden, werden Ports oft nach den jeweiligen Diensten benannt. Beispiele:

Ports sind wichtig, wenn Dienste oder öffentliche APIs (Application Programming Interfaces) angeboten werden. Auch beim Durchgriff auf private Geräte aus dem Internet, beispielsweise bei Smart Home-Anwendungen, sind private Ports wichtig.

Ports sind auf 16 Bit abgebildet, dass heißt 2 hoch 16 = 65535 Portnummern stehen zur Verfügung.

1.3.4.2 Datenstrom

TCP ist ein Datenstrom-Protokoll (stream oriented), man spricht auch von einem verbindungsorientierten Protokoll. Das bedeutet, es werden zwar einzelne Datenpakete gesendet, jedoch gibt es eine Verbindung, welche vor der Datenübertragung aufgebaut und danach wieder abgebaut wird, ganz im Gegenteil zu UDP.

Auf weitere Felder soll in diesem Zusammenhang nicht weiter eingegangen werden, da sich mit diesem Thema allein ein Buch füllen ließe. Das TCP-Protokoll ist das meistgenutzte dieser Schicht und dient zum verbindungsorientierten Datentransfer zwischen zwei Hosts.

1.3.5 User Datagram Protocol (UDP)

Dieses Protokoll ist verwandt mit TCP. Es unterscheidet sich allerdings in wichtigen Parametern und dient anderen Zwecken. So ist keine Fehlerkorrektur implementiert. Dies ist nicht für alle Arten von Datentransfers notwendig. Multimedia-Streams werden beispielsweise meist mit UDP übertragen, da es hier vor allem auf eine hohe Performance ankommt. Wenn bei bewegten Bildern einige Frames fehlen, fällt dies nicht unbedingt ins Gewicht. Wichtiger ist dann, dass die Information selbst übertragen wird, also der Inhalt des Films beim Empfänger ankommt. Andauerndes Stocken bei der Übertragung, weil fehlerhafte oder unvollständige Daten neu übertragen werden müssen, stört da mehr.

1.3.5.1 Multimedia und VoIP

UDP kommt standardmäßig bei der Abfrage von DNS-Informationen zum Einsatz. Hier bringt das Protokoll bei den zahlreichen kleinen Datenpaketen, die einen DNS-Server ständig erreichen, einen Performance-Vorteil. Weitere Anwendungen für dieses Protokoll sind Routingprotokolle wie RIP (Routing Information Protocol), TFTP (Trivial File Transfer Protocol) oder SNMP (Simple Network Management Protocol). Aber auch bei Multimedia und anderen Streaming Anwendungen wie VoIP kommt UDP zum Einsatz.

Zu beachten ist, dass UDP aufgrund der fehlenden Flusskontrolle und Fehlerkorrektur als nicht sehr sicheres Protokoll gilt. Deshalb ist es ein beliebtes Protokoll für Hacker, die beispielsweise mit Denial of Service-Attacken immer wieder von sich reden gemacht haben. Dabei werden Hosts mit einer Unmenge von UDP-Paketen überflutet, was zu deren Überforderung und damit der zeitweisen Lahmlegung führt.

1.3.6 Session Initiation Protocol (SIP)

VoIP (Voice over IP) nimmt weiter an Bedeutung zu. Auch wenn dieses Buch nicht über Multimedia und Telefonie handelt, darf dieses Protokoll in der Aufzählung der wichtigsten Internetprotokolle nicht fehlen. Wie der Name schon zum Ausdruck bringt, wird dieses Protokoll zum Aufbau und der Steuerung von Kommunikationssession aller Art verwendet. Weitere Informationen findest du im RFC 3261.

1.4 Die Hochsprachenprotokolle

Die Hochsprachenprotokolle arbeiten auf Schicht 7 des Referenzmodells bzw. Schicht 4 der IPS. Sie sind in der Regel textbasiert und übermitteln einfache Kommandos. Für die Arbeit mit Web-Anwendungen ist das Hypertext Transfer Protocol HTTP ausnahmslos das Wichtigste. Wichtig sind daneben auch das File Transfer Protocol FTP, das Network News Transfer Protocol NNTP (veraltend) und das Simple Mail Transfer Protocol SMTP, die nachfolgend im Überblick vorgestellt werden.

1.4.1 File Transfer Protocol (FTP)

Neben HTTP ist dieses Protokoll das Wichtigste beim tagtäglichen Einsatz im Internet. Es dient dem Datenaustausch zwischen FTP-Server und -Client, wobei der Client auf eine genau definierte Art und Weise Zugriff auf das Dateisystem des Servers erhalten kann.

Für den Zugriff auf einen FTP-Server bieten alle modernen Betriebssysteme verschiedene Arten von Clients. Dazu kommen viele grafische FTP-Clients.

1.4.2 Network News Transfer Protocol (NNTP)

Dieses Protokoll dient zum Nachrichtenaustausch zwischen sogenannten News-Servern und entsprechenden Clients. Es ist historisch gesehen eines der ältesten Protokolle, welches noch weit vor dem Einzug des Internets in den Alltag genutzt wurde. Das Protokoll arbeitet, anders als HTTP, nicht statuslos, sondern führt einen Message Pointer. Für die Kommunikation mit einem News-Server ist eine Anmeldung erforderlich.

Das Protokoll gilt inzwischen als veraltet. Nachrichtengruppen werden zunehmen durch Web-basierte Foren verdrängt, die mehr Gestaltungsspielraum ermöglichen.

1.4.3 Simple Mail Transfer Protocol (SMTP) / Extended SMTP (ESMTP)

SMTP kommt in Clientsystemen für das Versenden sowie bei Mailservern zum Senden und Weiterleiten von E-Mails zum Einsatz. Inzwischen hat sich der ESMTP-Standard durchgesetzt. Dieser ist in RFC 2821 spezifiziert und bietet erweiterte Funktionen zur Kommunikation zwischen SMTP-Client und -Server.

Wie viele Protokolle im Web-Umfeld ist auch diese Protokoll ASCII-Text basiert. Alle Nachrichten, welche vom Client zum Server gesendet werden, können dabei sowohl vom Menschen als auch von der Software interpretiert werden.

1.4.4 Hypertext Transfer Protocol (HTTP)

In diesem Abschnitt erfährst du das Wichtigste über HTTP, das in der Webserver-Programmierung eine herausragende Rolle spielt.

HTTP dient der Kommunikation mit Webservern. Es gibt die Versionen 1.0 (1996, RFC 1945), 1.1 (1999, RFC 2616) und 2.0 (2015, RFC 7540). Auf Seiten der Browser wird HTTP 1.1 gesprochen, einige neuere (Chrome, Edge) kennen bereits HTTP 2.0. Die Version 2.0 befindet sich heute (2017) in der Einführungsphase. Dazu kommen eine Reihe von Sub-Standards, die teilweise implizit benutzt werden:

Bei HTTP handelt es sich um ein verbindungs- oder statusloses Protokoll. Server und Client nehmen also nie einen besonderen Zustand ein, sondern beenden nach jedem Kommando den Prozess vollständig, entweder mit Erfolg oder mit einer Fehlermeldung. Es obliegt dem Kommunikationspartner, darauf in angemessener Weise zu reagieren.

1.4.4.1 Protokollaufbau, Header, Body

HTTP-Kommandos werden als ASCII-Text übertragen und können aus mehreren Zeilen bestehen. Die erste Zeile ist immer die Kommandozeile. Daran angehängt kann ein Message-Header (Nachrichtenkopf) folgen. Der Nachrichtenkopf enthält weitere Kopffelder, die das Kommando näher beschreiben. So ist in der Regel immer ein Content-Length-Kopffeld enthalten. Steht dort ein Wert größer als 0, folgen dem Nachrichtenkopf Daten. Die Daten werden also gleich zusammen mit dem Kommando gesendet, man spricht dann vom Body (Nachrichtenkörper) der Nachricht. HTTP versteht im Gegensatz zu anderen Protokollen den Umgang mit 8-Bit-Werten. Binärdaten, wie Bilder oder Sounds, müssen nicht konvertiert werden. Folgen dem HTTP-Kommando und den Nachrichtenkopf-Zeilen zwei Leerzeilen (Zeilenwechsel), so gilt das Kommando als beendet. Kommandos mit Nachrichtenkörper haben kein spezielles Ende-Zeichen. Das Content-Length-Kopffeld bestimmt, wie viele Bytes als Inhalt der Nachricht betrachtet werden.

1.4.4.2 Kommandoaufbau

Ein HTTP-Kommando hat immer folgenden Aufbau:

1 METHODE ID VERSION

Als METHODE wird das Kommando selbst bezeichnet.

Die folgende Tabelle zeigt die wichtigsten HTTP-Methoden auf einen Blick.

Tabelle: Auswahl HTTP-Methoden
Methode Bedeutung
CONNECT Verbindung zu einer TLS-Ressource aufbauen
DELETE Ressource löschen (siehe REST)
GET Ressource anfordern
HEAD Header der Ressource anfordern
LINK Verknüpfung zweier Ressourcen beantragen
OPTIONS Merkmale des Webservers erfragen, Auth-Preflight
POST Formulardaten an einen Serverprozess senden
PUT Ressource auf dem Webserver ablegen (siehe REST)
TRACE Kommando zurückschicken lassen
UNLINK Verknüpfung zwischen Ressourcen löschen

Beachte hier, dass die Methode unbedingt in Großbuchstaben geschrieben werden müssen, exakt wie in der Tabelle oben gezeigt.

Als Ressource werden all die Objekte bezeichnet, die übertragen werden können – in erster Linie also HTML-Dateien, Daten und Bilder.

Die ID einer Ressource kann beispielsweise eine Adresse oder ein Dateiname sein:

1 GET index.html HTTP/1.0

Dieses Kommando fordert die Datei index.html an.

1.4.4.3 Die HTTP-Statuscodes

Die Antwort auf ein Kommando besteht im Senden der Daten – wenn dies gefordert wurde – und einem Statuscode. Dem Statuscode folgen optionale Felder und, bei der Übertragung von Ressourcen, die Daten. Die Statuszeile hat folgenden Aufbau:

1 VERSION STATUSCODE STATUSTEXT

Der Statuscode ist eine dreistellige Zahl, von der die erste Ziffer (Hunderterstelle) die Zuordnung zu einer bestimmten Gruppe anzeigt.

Tabelle: HTTP-Antwortcodes (Auswahl)
Gruppe Code Name Bedeutung
1 100 Continue Weiter fortfahren
1 101 Switching Protocols Protokollwechsel erforderlich, z.B.
      von HTTP auf WebSockets
1 102 Processing Server bearbeitet die Anfrage, verhindert ggf.
      Timeout bei längere Verarbeitungszeit
2 200 OK Kommando erfolgreich (nach GET/POST)
2 201 Created Ressource wurde erstellt (nach PUT)
2 202 Accepted Authentifizierung akzeptiert (nach GET)
2 204 No Content Kein Inhalt oder nicht angefordert (GET)
3 301 Moved Permanently Ressource am anderen Ort
3 302 Found Ressource zeitweilig an anderem Ort
      (dies ist ein temporärer Zustand)
3 304 Not Modified Ressource wurde nicht verändert (steuert Proxy)
4 400 Bad Request Syntaxfehler (alle Kommandos)
4 401 Unauthorized Keine Autorisierung
4 403 Forbidden Nicht öffentlicher Bereich, Anfrage unzulässig
4 404 Not Found Ressource nicht gefunden
5 500 Server Error Serverfehler, Fehlfunktion der Serversoftware
      oder -applikation
5 503 Service Unavailable Dienst nicht verfügbar

Sicher kennst du den Fehler 404. Man geht davon aus, dass der Fehler beim Client liegt (Gruppe 4), also schlicht die falsche Ressource angefordert wurde. Du wirst schnell den Fehler 500 kennenlernen, der erzeugt wird, wenn ein Programm nicht funktioniert. Das Programm läuft auf dem Server und deshalb ist es ein Fehler der Gruppe 5.

1.4.4.4 Ablauf einer HTTP-Kommunikation

Der grundsätzliche Ablauf einer HTTP-Kommunikation besteht aus zwei Teilen – Anfrage (request) und Antwort (response). Dies sieht beispielsweise folgendermaßen aus:

Listing: Anfrage
1 GET http://www.joergkrause.de/ HTTP/1.1
2 Accept: text/html, application/xhtml+xml, image/jxr, */*
3 Accept-Language: de-DE,de;q=0.8,en-US;q=0.5,en;q=0.3
4 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; LCJB; \
5 rv:11.0) like Gecko
6 Accept-Encoding: gzip, deflate
7 Host: www.joergkrause.de
8 Connection: Keep-Alive
Listing: Antwort (nur Kopffelder, ohne Daten)
 1 HTTP/1.1 200 OK
 2 Date: Sun, 17 Jan 2016 10:59:09 GMT
 3 Server: Apache
 4 X-Powered-By: PHP/5.5.30
 5 Expires: Thu, 19 Nov 1981 08:52:00 GMT
 6 Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pr\
 7 e-check=0
 8 Pragma: no-cache
 9 X-Pingback: http://www.joergkrause.de/xmlrpc.php
10 Link: <http://wp.me/P6sMv6-12>; rel=shortlink
11 Set-Cookie: PHPSESSID=4744597c154b01a61e245292b8f1a897; path=/
12 Keep-Alive: timeout=2, max=200
13 Connection: Keep-Alive
14 Content-Type: text/html; charset=UTF-8
15 Content-Length: 27465
1.4.4.5 Kopffelder

An ein Kommando oder an die Statuszeile können weitere Felder angehängt werden, sogenannte Kopffelder (manchmal auch Kopfzeilen genannt, weil jedes Feld auf einer Zeile steht) oder kurz Header:

Feldname: Wert; Wert

Die Nachrichtenkopffelder können in drei Hauptgruppen aufgeteilt werden:

Eine typische Anwendung, die bei der Web-Programmierung auftreten kann, ist die Übergabe eines Nachrichtenkopffeldes, der einen besonderen Dateityp für das Herunterladen einer Datei angibt:

Content-Type: application/pdf; name=aspnet.pdf

Im Gegensatz zu anderen Protokollen ist die Länge eines Datenblocks im Content-length-Kopffeld festgelegt, irgendwelche Begrenzungszeichen gibt es nicht. Wichtig ist auch, dass der Server nach dem Verbindungsaufbau keine Antwort sendet. Nur das erste eintreffende Kommando löst eine Reaktion aus. Darin ist die Ursache zu sehen, wenn der Browser nach der Anforderung eines unerreichbaren Servers lange Zeit nicht reagiert. Als “Totsignal” wird einfach eine vorgegebene Zeitspanne gewartet, in welcher der Server auf das erste Kommando reagieren sollte.

1.4.5 HTTP 2.0

Die aktuelle Version von HTTP ist HTTP 2.0 (im Header als HTTP/2 bezeichnet), welche als RFC 7540 am 15. Mai 2015 veröffentlicht wurde.

Der Standard ist heute in den RFC 7540 und 7541 spezifiziert. Die Entwicklung war maßgeblich von Google (SPDY, spricht man aus wie “speedy”) und Microsoft (HTTP Speed+Mobility) mit jeweils eigenen Vorschlägen vorangetrieben worden. Ein erster Entwurf, der sich weitgehend an SPDY anlehnte, war im November 2012 publiziert und seither in mehreren Schritten angepasst worden.

Mit HTTP/2 soll die Übertragung beschleunigt und optimiert werden. Der neue Standard ist vollständig abwärtskompatibel zu HTTP/1.1.

Wichtige neue Möglichkeiten sind

Eine Beschleunigung ergibt sich hauptsächlich aus der neuen Möglichkeit des Zusammenfassens (Multiplex) mehrerer Anfragen, um sie über eine Verbindung abwickeln zu können. Die Datenkompression kann nun auch Kopfdaten mit einschließen. Statt dem bisher benutzten Gzip oder Deflate erreicht man dies mit dem neuem Spezialalgorithmus namens HPACK (RFC 7541).

Inhalte können binär kodiert übertragen werden. Um nicht auf serverseitig vorhersehbare Folgeanforderungen vom Client warten zu müssen, können Datenübertragungen teilweise vom Server initiiert werden (push-Verfahren).

Die ursprünglich geplante Option, dass HTTP/2 standardmäßig TLS (Transport Layer Security, früher SSL genannt, dient der Verschlüsselung) nutzt, wurde nicht umgesetzt. Allerdings kündigten Google und Mozilla für ihre Browser an, dass diese HTTP/2 nicht ohne Verschlüsselung unterstützen werden (siehe Application-Layer Protocol Negotiation). Aufgrund der Marktmacht muss man davon ausgehen, dass damit alle HTTP/2-Server zwingend TLS anbieten müssen.

Die verbreiteten modernen Browser unterstützen inzwischen HTTP/2. Darunter Google Chrome (auch unter iOS und Android) ab Version 41, Mozilla Firefox ab Version 36, Internet Explorer 11 und Edge unter Windows 10, Opera ab Version 28 (auch Opera Mobile ab Version 24) und Safari ab Version 8.

1.4.6 Ergänzende Standards

Flankiert wird HTTP durch weitere Standards, die entweder darauf aufsetzen oder ergänzend benutzt werden.

1.4.6.1 WebSockets

Das WebSocket-Protokoll ist ein auf TCP basierendes Netzwerkprotokoll, das entworfen wurde, um eine bidirektionale Verbindung zwischen einer Webanwendung und einem WebSocket-Server bzw. einem Webserver, der auch WebSockets unterstützt, herzustellen. Es entfallen bei WebSockets die durch den HTTP-Kopffelder verursachten zusätzlichen Daten.

Während bei einer reinen HTTP-Verbindung jede Aktion des Servers eine vorhergehende Anfrage des Clients erfordert, muss beim WebSocket-Protokoll der Client die Verbindung nur eröffnen. Der Server kann dann diese offene Verbindung aktiv verwenden und kann weitere Informationen an den Client senden, ohne auf eine neue Verbindung des Clients zu warten.

Die Anfrage wird mit einem speziellen Kopffeld aus HTTP heraus initiiert:

1 GET /chat HTTP/1.1
2 Host: server.example.com
3 Upgrade: websocket
4 Connection: Upgrade
5 Sec-WebSocket-Key: dJhoIeNrbgBKZrBabu5sZe==
6 Origin: http://example.com
7 Sec-WebSocket-Protocol: chat, superchat
8 Sec-WebSocket-Version: 13

Die Antwort sollte dann den Statuscode 101 enthalten:

1 HTTP/1.1 101 Switching Protocols
2 Upgrade: websocket
3 Connection: Upgrade
4 Sec-WebSocket-Accept: sjpoLeBrTgai9sYazGheRe+KxOo=
5 Sec-WebSocket-Protocol: chat

Durch den HTTP-Statuscode 101 und die folgenden zwei Zeilen erklärt der Server, dass er mit dem Wechsel des Protokolls einverstanden ist.

Technisch betrachtet startet bei WebSocket, wie bei HTTP, der Client eine Anfrage, mit dem Unterschied, dass nach der Übertragung der Daten zum Verbindungsaufbau die zugrundeliegende TCP-Verbindung bestehen bleibt und Übertragungen in beide Richtungen ermöglicht.

1.4.6.2 WebDAV

WebDAV (Web-based Distributed Authoring and Versioning) ist ein offener Standard zur Bereitstellung von Dateien im Internet. Dabei können Benutzer auf ihre Daten transparent zugreifen, also in schreibend und lesend.

Technisch gesehen ist WebDAV eine Erweiterung des Protokolls HTTP/1.1, die bestimmte Einschränkungen von HTTP aufhebt. Mit WebDAV können Dateien und auch ganze Verzeichnisse übertragen werden. Zudem ist eine Versionskontrolle spezifiziert.

Da der schreibende Zugriff auf Web-Server ziemlich riskant ist, hat WebDAV keine massive Verbreitung gefunden. Es wird, wenn überhaupt, zum Veröffentlichen von Anwendungen aus einer lokalen Entwicklungsumgebung heraus benutzt. Einige Web-Hoster und Provider bieten dies als leistungsfähige Alternative zu FTP an.

1.5 REST

REST steht für REpresentational State Transfer und bezeichnet einen Architekturstil (oder auch “Programmierparadigma für verteilte Systeme”, siehe dazu auch Wikipedia), der bereits häufig benutzte Techniken und Protokolle zusammenfasst und für die Datenübertragung nutzt. Dies umfasst:

1.5.1 Merkmale

Die technischen Merkmale eines REST-Dienstes sind:

1.5.1.1 Adressierbarkeit

Jeder REST-konforme Dienst hat eine eindeutige Adresse, den Uniform Resource Locator (URL). Zusätzlich zum URL, der den Dienst selbst adressiert, verwendet REST auch Uniform Resource Identifier (URI), um einzelne Ressourcen zu bezeichnen.

1.5.1.2 Repräsentationsvariabel

Die unter einer Adresse zugänglichen Dienste können unterschiedliche Darstellungsformen (Repräsentationen) haben. Ein REST-konformer Server kann beispielsweise HTML, JSON oder XML liefern. Dies können Daten oder Beschreibungen von Daten sein (Meta-Daten).

1.5.1.3 Zustandslosigkeit

Jede REST-Nachricht enthält alle Informationen, die für den Server bzw. Client notwendig sind, um die Nachricht zu verstehen. Weder der Server noch die Anwendung soll Zustandsinformationen zwischen zwei Nachrichten speichern. Man spricht daher von einem zustandslosen (stateless) Protokoll. Jede Anfrage eines Clients beinhaltet sämtliche Informationen über den Anwendungszustand, die vom Server benötigt werden.

1.5.1.4 Skalierbarkeit

Die Zustandslosigkeit begünstigt die Skalierbarkeit eines Dienstes. Da jede Anfrage zu einer definierten Reaktion führt und keine Voraussetzungen auf einer bestimmten Maschine vorhanden sein müssen, können Lastverteiler Anfragen auf mehrere Maschinen verteilen, ohne dass dies Änderungen an der serverseitigen Verarbeitung nach sich zieht.

1.5.1.5 Allgemeingültig

HTTP schreibt vor, dass GET “sicher” (safe) sein muss. Dies bedeutet, dass diese Methode nur Informationen beschafft und keine Nebeneffekte hat. Die Methoden GET, HEAD, PUT und DELETE müssen idempotent sein, was bedeutet, dass das mehrfache Absenden der gleichen Anforderung sich nicht anders auswirkt als ein einzelner Aufruf.

1.5.1.6 Erweiterbar

Erweiterbarkeit heißt, dass später erfolgende Erweiterungen der Ressourcenbasis, zusätzliche Funktionen, mehr Daten, anderen Repräsentationen oder Skalierungsmaßnahmen sich nicht auf die bestehenden Clients auswirken dürfen.

1.5.2 Beispiel

Ein Merkmal von REST ist die Beschreibung von Ressourcen. Dazu gehören Links zu weiterführenden Elementen. Bestehen zwischen Daten Beziehungen, so ist dies in der Antwort zu erkennen. Eine einfach Abfrage nutzt das Kommando GET (siehe auch Abschnitt zu HTTP weiter unten).

GET /book/2605
 1 HTTP/1.1 200 OK Content-Type: text/xml
 2 <?xml version="1.0"?>
 3 <book xmlns:xlink="http://www.w3.org/1999/xlink">
 4     <cat xlink:href="http://shop.texxtoor.de/cat/122">122</cat>
 5     <author xlink:href="http://shop.texxtoor.de/author/1">1</author>
 6     <author xlink:href="http://shop.texxtoor.de/author/2">2</author>
 7     <title>JADE</title>
 8     <desc>Die Template-Engine JADE</desc>
 9     <price>2,99</price>
10     <type>Paperback</type>
11 </book>

Hier verweisen die URIs einiger Elemente auf abhängige Ressourcen. Der Client kann dies nutzen, um einen Teil der Benutzeroberfläche dynamisch zu erstellen.

1.5.3 URI

URI steht für Uniform Resource Identifier und ist das Verfahren zum Konstruieren der Adressen. Im Zusammenhang mit REST ist oft der Begriff RESTful zu sehen. Es ist wichtig zu verstehen, dass damit die korrekte Implementierung von REST gemeint ist. Das heißt nicht, das lediglich HTTP benutzt wird, sondern auch, dass die Routen, die zum Abruf von Daten und zum Auslösen von Aktionen benutzt werden, bestimmten Kriterien gehorchen.

URI wird oft mit URL (Uniform Resource Locater) verwechselt. URL ist eine Spezialform des URI. URLs dienen der Adressierung von Webseiten im Browser. URIs können dies und noch einiges andere adressieren. In URLs werden zum Anhängen von Daten Parameter benutzt, die durch ein ?-Zeichen abgetrennt sind. Diesen Teil nennt man Querystring. Folgendes sind typische Anwendungsfälle:

Der Teil book=2605 ist der Querystring. Dies ist nicht RESTful. RESTful verlangt, dass der Datenteil als Teil des URL erfasst wird. Routen – das sind Adressierungsschemata auf Basis von URIs – haben definierte Abschnitte, denen eine Bedeutung zugewiesen wird. Diese Zuweisung ist willkürlich (Sache des Entwicklers), läuft aber häufig nach einem einfachen Prinzip:

/ressource/id

Oder etwas komplexer:

/ressource/id/aktion

RESTful würden die Beispiele eben wie folgt aussehen:

Freilich sind hier immer noch viele Optionen vorhanden. Deshalb ein paar Regeln:

/books/search?filter=title&value=JADE

/books/select/quarter=2;year=2016

Weniger wichtig, aber für guten Stil sinnvoll:

1.5.4 HTTP-Methoden für REST

In REST werden spezifische HTTP-Methoden benutzt, um Aktionen auf dem Server auszulösen. Konkret eingesetzt werden:

Es ist nicht zwingend notwendig, dies mit SQL zu vergleichen, ein einfaches Mapping kann REST aber durchaus darstellen:

Tabelle: Mapping von REST auf SQL
HTTP (REST) SQL
GET SELECT
POST INSERT
PUT UPDATE
DELETE DELETE

In HTTP sieht das beispielhaft folgendermaßen aus (… steht für typische Kopffelder):

1 POST /basket/2605
2 ...
3 name=Neuer Artikelname

Hierbei ist die URI ein relativer Pfad zur Ressource. basket bezeichnet die Route zu einem Controller, der sich um den Warenkorb kümmert. Die Route erwartet eine ID, die hier 2605 enthält. Damit ist im Warenkorb ein Element mit dem Primärschlüssel 2605 gemeint. Dieses Element hat eine Eigenschaft name der der neue Text “Neuer Artikelname” zugewiesen wird.

Mittels PUT wird eine Ressource wie folgt geändert:

 1 PUT /basket
 2 
 3 <book>
 4   <title>Pug</title>
 5   <desc>
 6     Die Template-Engine Pug
 7   </desc>
 8   <price>2,99</price>
 9   <type>Paperback</type>
10 </book>

Da eines der Merkmale von REST die Selbstbeschreibung ist, gibt PUT einen Link zur geänderten Ressource zurück:

1 HTTP/1.1 201 OK
2 Content-Type: text/xml;
3 Content-Length: 34
4 
5 http://shop.texxtoor.de/basket/2605

Das Löschen der Ressource erfolgt ähnlich:

1 DELETE /basket/2605

1.5.5 MIME

MIME steht für Multipurpose Internet Mail Extensions und wurde ursprünglich dazu entwickelt, Dokumente in E-Mails einzubetten. Dabei wird eine beschreibende Kopfzeile (header) benutzt, um das ursprüngliche Format anzuzeigen. Der Client kann dies dann wieder herstellen. Typisch ist die Zweiteilung des Formats und die Benutzung der Kopfzeile Content-Type:

gruppe/detail

Für ein Bild sieht das nun folgendermaßen aus:

Content-Type: image/jpeg

Eine genaue Beschreibung, die über das hier für REST benötigte hinausgeht, findest du auf Wikipedia.

Für REST wird folgendes benutzt:

1.5.6 JSON

Zur Kommunikation zwischen Client und Server wird JSON eingesetzt wird. JSON (JavaScript Object Notation), gesprochen wie der Name “Jes’n”, ist ein kompaktes Format in lesbarer Textform zum Zweck des Datenaustauschs zwischen Anwendungen. Obwohl der Name auf eine alleinige Verwendung in JavaScript hindeutet, ist JSON ein unabhängiges Format, das theoretisch in jeder Programmierumgebung eingesetzt werden kann.

Der am meisten betonte Unterschied von JSON zu XML ist die etwas kompaktere Kodierung von Datenstrukturen, wodurch im Gegensatz zu XML weniger Verwaltungsdaten produziert werden. Außerdem kann JSON beispielsweise in JavaScript direkt in ein JavaScript-Objekt umgesetzt werden. XML ist hingegen vielseitiger als JSON einsetzbar, das keine Auszeichnungssprache, sondern nur ein Datenaustauschformat ist. XML genießt weiterhin eine weite Verbreitung. Beide Formate sind nicht unbedingt zum Repräsentieren von großen Binärdaten geeignet.

JSON kennt Objekte, Arrays, Zeichenketten, Zahlen, Boolesche Werte und null. Daten können beliebig verschachtelt werden, beispielsweise ist ein Array von Objekten möglich. Als Zeichenkodierung benutzt JSON UTF-8.

1.5.6.1 Die JSON-Formatdefinition

Ein Objekt wird mit geschweiften Klammern umschlossen { }. Es kann eine durch Kommata geteilte, ungeordnete Liste von Eigenschaften enthalten.

JSON darf keine Kommentare enthalten, wie sie beispielsweise in JavaScript erlaubt wären.

Eine Eigenschaft besteht aus einem Schlüssel und einem Wert, getrennt durch einen Doppelpunkt. Der Schlüssel ist eine Zeichenkette. Der Wert ist ein Objekt, ein Array, eine Zeichenkette, eine Zahl oder einer der Ausdrücke true, false oder null. Ein Array beginnt und endet mit eckigen Klammern [ ]. Es kann eine durch Kommata geteilte, geordnete Liste von Werten enthalten. Eine Zeichenkette beginnt und endet mit Anführungszeichen ("). Sie kann Unicode-Zeichen und Escape-Sequenzen enthalten. Ein Boolescher Wert wird durch die Ausdrücke true bzw. false dargestellt – ohne Anführungszeichen. Eine Zahl ist eine Folge der Ziffern 0−9. Diese Folge kann durch ein negatives Vorzeichen – eingeleitet und einen Dezimalpunkt unterbrochen sein. Die Zahl kann durch die Angabe eines Exponenten e oder E ergänzt werden, dem ein Vorzeichen “+” oder “-“ und eine Folge der Ziffern 0-9 folgt. Leerraumzeichen sind beliebig verwendbar.

Listing: Beispiel eines JSON-Blocks
 1 {
 2   "CreditCard"    : "Visa",
 3   "Number"        : "1234-5678-9012-3456",
 4   "Owner"         :
 5   {
 6     "LastName"    : "Krause",
 7     "Firstname"   : "Jörg",
 8     "Gender"	    : "\"male\"",
 9     "Preferences" : [
10       "Golf",
11       "Reading",
12       "Badminton"
13     ],
14     "Age"         : null
15   },
16   "Deckung"       : 10000,
17   "Währung"       : "EURO"
18 } 

Wenn du mehr über JSON lesen möchtest, könnten folgende Quellen interessant sein:

1.5.7 Das Format ATOM

ATOM steht für Atom Syndication Format, ein plattformunabhängiges Format zum Austausch von Feeds. Es hat damit denselben Zweck wie das bekanntere RSS, das in der neuesten Version 2.0 für Really Simple Syndication steht. ATOM gilt als designierter Nachfolger von RSS 2.0. ATOM selbst ist für verschiedene Zwecke definiert, wobei hier auf ASF (ATOM Syndication Format) Bezug genommen wird. Neben der reinen Feed-Verteilung kann ATOM für Newsletter und ähnliche Zwecke eingesetzt werden. ATOM wurde in der RFC 4278 veröffentlicht. Der MIME-Typ ist application/atom+xml.

Listing: Typischer ATOM-Block
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <feed xmlns="http://www.w3.org/2005/Atom">
 3   <author>
 4     <name>Jörg Krause</name>
 5   </author>
 6   <id>urn:uuid:60a76c80-9926-9905-1964-0003939e0af6</id>
 7  
 8   <entry>
 9     <title>Neues aus der Web-Welt</title>
10     <link href="http://hanser.de/2010/08/08/atom-wcf"/>
11     <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-01723243189a</id>
12     <updated>2016-12-08T12:50:07Z</updated>
13     <summary>Alles über Web</summary>
14     <content>Hier steht der gesamte Text</content>
15   </entry>
16 </feed> 

1.5.8 Grenzen von REST

REST ist für kleine und mittlere Umgebungen perfekt. Es ist ausreichend, wenn die Komplexität der Abfragen überschaubar ist. Da jedoch alles eine Ressource ist, wird es unübersichtlich, wenn es sehr viele derartige Ressourcen gibt. An dieser Stelle sind komplexere Abfragesprachen gefragt, die Mehrfachzugriffe und Abhängigkeiten durch entsprechende Syntaxkonstrukte vereinfachen.

Etabliert haben sich hier zwei derartige Standards:

GraphQL basiert auf JSON-Paketen, in denen einen Abfrage formuliert wird. Entsprechend muss fast immer mit POST gearbeitet werden, weil auch bei Abfragen Daten zum Server übermittelt werden. GraphQL erlaubt komplexe Konstrukte und erfordert eine explizite serverseitige Unterstützung. GraphQL ist sehr auf die Web-Welt zugeschnitten und hat in reinen Web-Applikationen Vorteile.

ODATA ist dagegen bei Abfragen URL-basiert und kann GET benutzen. Die Abfragen sind einfacher, vielefältige Filter sind aber auch hier möglich. ODATA ist breiter aufgestellt, wenn es um Umgebungen außerhalb der Web-Welt geht.

1.6 GraphQL

GarphQL erschien 2015 und hatte von Beginn an starke Unterstützung, weil es eine echte Herausforderung beim Umgang mit REST-Diensten adressiert. Bei komplexeren Systemen, vor allem solchen, die mit Hilfsmitteln wie Swagger definiert werden, explodiert regelmäßig die Anzahl der Endpunkte. Der Dienst wird unübersichtlich und schwer wartbar. Darüberhinaus setzt der Dienst auf eine weitgehende Abstraktion von den Daten und überlässt es dem Client, die Daten zu filtern oder zu sortieren. In Anbetracht starker Datenbanken und großer Datenbestände eine eher schlechte Architektur, die regelmäßig zu Performance-Katastrophen führt.

Ursprünglich in Ruby und Skala geschrieben steht GraphQL als Abfragesprache praktisch auf allen Plattformen zur Verfügung. Immer wenn das führende Format JSON ist, hat GraphQL deutliche Vorzüge gegenüber ODATA, was sich eher im XML-Umfeld wohlfühlt. Die aktuelle Referenzimplementierung ist in JavaScript geschrieben und via npm verfügbar. Der Quellcode ist auf Github zu finden.

1.6.1 Implementierungen

Folgende Umgebungen werden explizit unterstützt:

1.6.2 Abfragen

Die einfachste Abfrage bei GraphQL fragt nach Feldern eines Objekts. Dies könnte etwa folgendermaßen aussehen:

1 {
2   table_name {
3     field
4   }
5 }

Beachte dabei, dass dies kein gültiges JSON ist – GraphQL ist eine eigene Abfragesprache, die bei Abfragen simplifizierte Konstrukte nutzt. Die Antwort ist dagegen JSON und kann so einfach verarbeitet werden:

1 {
2   "data": {
3     "table_name": {
4       "field": 12345
5     }
6   }
7 }

Neben der vereinfachten Syntax hat GraphQL eine Eigenschaft, die JSON gänzlich fehlt: Kommentare sind erlaubt.

1 {
2   # Die Ressource
3   table_name {
4     # Das Feld
5     field
6   }
7 }
1.6.2.1 Argumente

Argumente werden direkt an die Namen gesetzt, ohne weitere geschweifte Klammern:

1 {
2   address(id: 1000) {
3     name,
4     city,
5     street
6   }
7 }

Argumente sind auf jeder Ebene möglich, was weitaus flexibler als bei REST ist.

1 {
2   address(id: 1000) {
3     name,
4     city,
5     street,
6     birthday(unit: datetime)
7   }
8 }
1.6.2.2 Aliase

Ein Feld kann immer nur mit einem Satz Argumente abgerufen werden. Soll dasselbe Feld in unterschiedlicher Weise abgerufen werden, so werden dafür Aliase eingesetzt. Folgende Abfrage bezieht sich auf das Feld hero:

1 {
2   empireHero: hero(episode: EMPIRE) {
3     name
4   }
5   jediHero: hero(episode: JEDI) {
6     name
7   }
8 }

Der Alias empireHero und der Alias jediHero dienen der Unterscheidung. In der Antwort werden die Aliase wiederholt, weil man so die Ergebnisse zuordnen kann:

 1 {
 2   "data": {
 3     "empireHero": {
 4       "name": "Luke Skywalker"
 5     },
 6     "jediHero": {
 7       "name": "R2-D2"
 8     }
 9   }
10 }
1.6.2.3 Fragmente

Die beim Alias bereits angesprochene einfache Abfragestrategie mit eindeutigen Feldnamen kann bei komplexen Abfragen schnell dazu führen, dass umfangreiche Strukturen wiederholt werden. Dies lässt sich mit Fragmenten entschärfen. Fragmente sind vordefinierte Konstrukte, eingeleitet mit dem Operator ... (drei Punkte).

 1 {
 2   leftComparison: hero(episode: EMPIRE) {
 3     ...comparisonFields
 4   }
 5   rightComparison: hero(episode: JEDI) {
 6     ...comparisonFields
 7   }
 8 }
 9 
10 fragment comparisonFields on Character {
11   name
12   appearsIn
13   friends {
14     name
15   }
16 }

comparisonFields ist hier das Fragment, das zweimal (Zeile 3 und Zeile 6) benutzt wird.

1.6.2.4 Operationen

Bislang wurde davon ausgegangen, dass alles Abfragen sind. Das ist jedoch nicht immer der Fall, denn dynamischere Konstrukte lassen sich mit Variablen bilden. Dazu muss der Dienst aber zwischen einer Definition und einer Abfrage unterscheiden können. Abfragen werden, außer in der bereits gezeigten vereinfachten Form, mit query erstellt.

1 query HeroNameAndFriends {
2   hero {
3     name
4     friends {
5       name
6     }
7   }
8 }

Zulässigen Operationen sind:

Der Name ist zwingend erforderlich. Er wird jedoch nur zum Loggen auf der Serverseite benutzt, er erscheint nicht in der Antwort und kann deshalb auch nicht zur Referenzierung benutzt werden.

1.6.2.5 Variablen

Variablen erleichtern die Angabe von sich häufig wiederholenden Daten.

1 query HeroNameAndFriends($episode: Episode) {
2   hero(episode: $episode) {
3     name
4     friends {
5       name
6     }
7   }
8 }

$episode ist hier die Variable. Sie wird in einem separaten Verzeichnis definiert (dort ohne das $-Zeichen):

1 {
2   "episode": "JEDI"
3 }

Der Name für diesen Bereich ist variables:

 1 "query": "query ($username: String!){
 2     blog {
 3       user(username: $username) {
 4         username
 5         comment
 6       }
 7     }
 8 }",
 9 "variables":"{
10     \"username\":\"Joerg\"
11 }"

Dies ist ein Beispiel für serialisiertes JSON, wie es ein Web-Client erzeugt. Die Variable liegt außerhalb der Query-Struktur, aber im selben Paket.

Variablen können Standardwerte haben, die bei fehlender Definition benutzt werden, sodass sich Abfragen allein mittels veränderlicher Variablen robust modifizieren lassen:

1 query HeroNameAndFriends($episode: Episode = "JEDI") {
2   hero(episode: $episode) {
3     name
4     friends {
5       name
6     }
7   }
8 }

Der Vorteil macht sich bemerkbar, wenn man im JavaScript GraphQL-Abfragen zusammenbaut. Dies geht mit Variablen deutlich einfacher als mit den komplexen Zeichenketten-Verknüpfungen, die sonst erforderlich wären.

1.6.2.6 Direktiven

Direktiven dienen ähnlich wie Variablen dazu, die Abfrage noch dynamischer zu machen und damit den Zusammenbau zu vereinfachen. Folgende Direktiven gibt es:

Es handelt sich also quasi um Bedingungen. In der folgenden Abfrage bestimmt die Variable withFriends, ob die Eigenschaft friends überhaupt in die Abfrage mit einbezogen wird.

1 query Hero($episode: Episode, $withFriends: Boolean!) {
2   hero(episode: $episode) {
3     name
4     friends @include(if: $withFriends) {
5       name
6     }
7   }
8 }
1.6.2.7 Mutationen

Mutationen dienen dem Ändern von Daten. Die grundlegende Syntax sieht folgendermaßen aus:

1 mutation CreateReviewForEpisode($ep: Episode!, 
2                                 $review: ReviewInput!) {
3   createReview(episode: $ep, review: $review) {
4     stars
5     commentary
6   }
7 }

Diese Abfrage benötigt folgende Variablen:

1 {
2   "ep": "JEDI",
3   "review": {
4     "stars": 5,
5     "commentary": "This is a great movie!"
6   }
7 }

Hier wird also ein neuer Datensatz erzeugt. Im Ergebnis wird der neue Datensatz zurückgegeben.

1.6.2.8 Schematas und Typen

Die vorhergehenden Beispiele haben bereits Typen benutzt – sowohl skalare als auch komplexe Typen. Folgende Skalare werden unterstützt:

Eigene einfache Typen werden mit scalar erstellt:

scalar Date

Wie ein derartiger Typ behandelt wird, muss in der Implementierung selbst entschieden werden. Ohne weitere Maßnahmen sind dies alles Zeichenketten.

Eigene komplexe Typen können mit type erstellt werden:

1 type Character {
2   name: String!
3   appearsIn: [Episode]!
4 }

Enumerationen (Aufzählungen) sind ebenso möglich, um Wertemengen zu begrenzen:

1 enum Episode {
2   NEWHOPE
3   EMPIRE
4   JEDI
5 }

Um anzuzeigen, dass eine Liste erwartet wird, kann die von JavaScript bekannte Array-Syntax benutzt werden:

field: [String!]

Wird erlaubt, nichts zu übertragen, steht der spezielle Typ null zur Verfügung.

Typen lassen sich von Schnittstellen mit interface ableiten, um die Wartbarkeit komplexer Typsysteme zu erhöhen.

 1 interface Character {
 2   id: ID!
 3   name: String!
 4   friends: [Character]
 5   appearsIn: [Episode]!
 6 }
 7 
 8 type Human implements Character {
 9   id: ID!
10   name: String!
11   friends: [Character]
12   appearsIn: [Episode]!
13   starships: [Starship]
14   totalCredits: Int
15 }
16 
17 type Droid implements Character {
18   id: ID!
19   name: String!
20   friends: [Character]
21   appearsIn: [Episode]!
22   primaryFunction: String
23 }

Ähnlich wie bei TypeScript lassen sich Typen zu Unions kombinieren. Ein Feld kann dann mehrere Typen aufnehmen, aber keine beliebigen Werte.

1 union SearchResult = Human | Droid | Starship