REST-Services mit Spray

Werkzeuge  –  0 Kommentare

REST-Services sind aus modernen Anwendungsarchitekturen nicht mehr wegzudenken und die Standard-Technik, um Drittsysteme mit einer Anwendung interagieren zu lassen. Spray bietet für Scala eine Möglichkeit, aus Akka-Anwendungen heraus REST-Services anzubieten.

Über REST-Services läuft die Kommunikation mit JavaScript-basierten Clients oder mobilen Apps. Viele Anbieter von Cloud-Diensten (etwa Twitter oder GitHub) bieten REST-APIs an, damit andere ergänzende Produkte oder Apps entwickeln können. Die Frage ist also nicht, ob eine Anwendung REST-Services bereitstellt, sondern viel mehr wie.

Im Java-Umfeld hat sich mit JAX-RS ein Standard für das Implementieren von REST-Services etabliert. Er ist Bestandteil des Java-EE-Stacks und mittlerweile weit verbreitet. Wenn man jedoch aus einer in Scala implementierten Anwendung REST-Services anbieten will, gibt es neben den etablierten Optionen aus dem Java-Umfeld weitere Alternativen. Eine davon ist Spray.

Spray hebt sich von allen anderen Werkzeugen ab, da es direkt auf dem Akka-Framework aufsetzt. Es basiert damit auf dem Aktorenmodell und nutzt dessen asynchrones Programmierkonzept. Möchte man also eine Akka nutzende Anwendung um REST-Services erweitern, ist Spray quasi die natürliche Wahl. Es ist Bestandteil des Typesafe-Stacks und wird in Zukunft weiter in Akka integriert werden. Als Akka HTTP entwickelt es sich zudem zu einem zentralen Bestandteil des Play-Frameworks.

Im Gegensatz zu Werkzeugen wie Jersey oder Scalatra ist Spray kein komplettes Framework, sondern eine Sammlung mehrerer spezialisierter Bibliotheken. Eine Anwendung kann also leicht nur Teile verwenden und auf nicht benötigte Elemente verzichten. Beispiele für die separat nutzbaren Bibliotheken sind eine Routing-DSL, ein Datenmodell für HTTP oder ein HTTP-Server.

Im Folgenden wird vorausgesetzt, dass der Leser über Grundkenntnisse der Entwicklung mit Scala und Akka verfügt.

Mit spray-can zum REST-Dienst

Der vorliegende Artikel konzentriert sich auf die Verwendung von Spray mit dem Toolkit spray-can. Es lässt sich aber auch innerhalb eines Servlet-3.0-Containers (zum Beispiel Tomcat 7) betreiben. Spray nutzt dabei intensiv die in Version 3.0 der Servlet-Spezifikation hinzugekommene Möglichkeit der asynchronen Requestbearbeitung.

spray-can unterscheidet sich konzeptionell deutlich von herkömmlichen HTTP-Servern oder Servlet-Containern. Es setzt technisch auf Akka IO auf, einer Aktor-basierten API für IO-Operationen. Letztere werden nicht über Methodenaufrufe, sondern durch den Austausch von Nachrichten zwischen Aktoren abgebildet. spray-can ruft Methoden in Handler-Klassen also nicht zur Bearbeitung von Requests auf, sondern stellt dem Handler-Aktor Nachrichten in Form von Case-Klassen zu. Das folgende Beispiel soll das Prinzip verdeutlichen, indem ein einfacher Aktor erzeugt wird, der auf jeden Request mit "Hello, World!" antwortet:

class SimpleHttpHandler extends Actor {
def receive = {
//register myself as a connection handler for the new connection
case _: Http.Connected => sender ! Http.Register(self)
//respond any http request with "Hello, world!"
case _: HttpRequest => sender ! HttpResponse(entity="Hello, World!")
}
}

Im Anschluss lässt sich der erstellte Aktor als Handler für den spray-can-Server verwenden. Mit dieser Grundlage kann der Entwickler ein neues Aktorensystem samt einer Instanz des oben beschriebenen Aktors erstellen und im Anschluss einen eingebetteten spray-can-Server mit dem erzeugten Aktor als Handler starten:

object SimpleSprayCanApp extends App {
// create a new Actor system
implicit val system = ActorSystem()
// create a new instance of the handler actor
val handler = system.actorOf(Props[SimpleHttpHandler], name =
"handler")
// start the spray-can server, bind to port 8080, register actor
//as handler
IO(Http) ! Http.Bind(handler, interface = "localhost", port=8080)
}

Die Bibliothek spray-http umfasst ein Datenmodell, um das HTTP-Protokoll abzubilden. Es ist Scala-typisch in Form unveränderlicher Case-Klassen gehalten. Dadurch lässt sich mit den üblichen Scala-Mitteln arbeiten, im obigen Codeausschnitt wird beispielsweise Pattern Matching verwendet. spray-can und das dazugehörige Datenmodell aus spray-http sind die Basis für die weitere Entwicklung von REST-Services. Für die normale Entwicklung ist aber der Umgang mit den Bestandteilen des HTTP-Protokolls viel zu umständlich. An der Stelle kommt nun die Routing-DSL von Spray zum Zuge, um die Arbeit zu erleichtern.

Das Routing hat die Aufgabe, die für einen Request passende Funktion zu dessen Beantwortung zu finden. Dazu werden die Request-URI, die HTTP-Methode und gegebenenfalls weitere Parameter des Requests in Kombination mit passenden Regeln herangezogen. Ein Beispiel für eine solche Regel wäre "die URI des Requests endet mit '/foo'". Bei JAX-RS werden die Routing-Regeln durch Annotationen (@Path, @GET, ...) abgebildet. Spray verwendet die Routing-DSL zur Formulierung der Regeln.