Aus Linux-Magazin 09/2017

Haskell-Framework fürs Web

© Pablo Hidalgo, 123RF

Das Yesod-Framework setzt neben den gängigen Webtechnologien wie HTML, Javascript und CSS auf einen Haskell-Compiler. Dieser optimiert aggressiv und überprüft jede Funktion auf ihre Korrektheit.

Frameworks fürs Web existieren wie Sand am Meer, die meisten basieren auf den Programmiersprachen PHP und Javascript, andere verwenden Python, Ruby, Go oder dergleichen. Greift ein Entwickler zu WordPress [1], Drupal [2] oder Joomla [3], muss er in der Regel lediglich den Kern auf dem Server entpacken und weitere Module ergänzen. Spielt er gewissenhaft und zeitnah Sicherheits-Aktualisierungen ein, kommt auch die übliche Malware meist auf keinen grünen Zweig.

Doch es gibt auch durchaus einige Gründe, die für den Einsatz exotischer Frameworks wie des auf Haskell [4] basierenden Yesod [5] sprechen. Nicht nur seine geringere Verbreitung, sondern auch die in den Compiler eingebaute Sicherheit (Haskell ist typsicher) machen Angriffe teuer bis unmöglich und SQL- und Javascript-Injections unwahrscheinlich. Zudem verarbeitet der Haskell-Compiler GHC [6], der seit April 1990 in Version 1.0 existiert und auf dem flotten C-Compiler basiert, Anfragen an die Webseite deutlich effizienter als viele andere Programmiersprachen. Da Haskell zu den funktionalen Programmiersprachen gehört, machen sich auch an anderen Stellen Erleichterungen bemerkbar, etwa beim Multithreading.

Entwickler treibt aber vor allem die Frage um: Wie klappt der Einstieg in das Framework? Denn Haskell gilt als schwer zu erlernen, orientiert sich stark an der mathematischen Logik und verwendet viele abstrakte Konzepte wie Monaden und Category Theory. Hier hilft ein Framework wie Yesod, das beim Umstieg auf Haskell dank vorgefertigter Komponenten für schnelle Erfolge sorgt und die immer noch steile Lernkurve ein wenig abflacht. Der Artikel hilft bei den ersten Schritten mit Yesod.

Installation

Für die Installation des Framework steht Stack [7] bereit, mit dem der Entwickler darüber hinaus ein Softwareprojekt einrichtet. Der Vorgang unterscheidet sich von Betriebssystem zu Betriebssystem, der Artikel beschreibt ihn für Fedora 25, das zunächst einige Pakete benötigt, um Stack einsatzfähig zu machen. Um sie zu holen, bindet der Entwickler mit »dnf« (Listing 1) das inoffizielle Repository unter [8] ein.

Listing 1

Stack auf Fedora 25

01 dnf install perl make automake gcc gmp-devel libffi zlib zlib-devel xz tar git gnupg dnf-plugins-core
02 dnf copr enable petersen/stack
03 dnf install stack

Um ein neues Yesod-Projekt zu starten, genügt es, den Haskell-Compiler lokal zu installieren:

cd
stack setup

Nach der Installation wartet der Haskell-Compiler unter »~/.stack/programs/x86_64-linux/GHC-Version/bin«. Zusätzliche Pakete, die ein Yesod-Projekt benötigt, installiert bei Bedarf ein simples »stack install Paketname« nach.

Homebanking

Ist diese erste Hürde genommen, beginnt die eigentliche Arbeit. Yesod unterstützt diverse bekannte Datenbanken, darunter Mongo DB, SQlite und – ansatzweise – Redis. Der Artikel beschreibt die Integration von PostgreSQL [9] und MySQL [10]. Der Entwickler erzeugt zunächst ein neues Projekt, indem er den folgenden Befehl eingibt:

stack new Projektname yesod-Datenbank

Die »Datenbank« ersetzt er durch einen gültigen Wert, den er etwa der Tabelle unter [11] entnimmt, also »yesod-postgres« oder »yesod-mysql«.

Soll die Webanwendung die Daten in eine MySQL-Datenbank schaufeln, muss diese zuvor bereits im Hintergrund laufen. Das bewirken die Schritte aus Listing 2. Anschließend wechselt der Entwickler in das von Stack erzeugte Projektverzeichnis und bearbeitet die Datei »config/settings.yml«. Unterhalb der Überschrift »database:« passt er die Einträge für den Datenbankbenutzer, den Host und den Namen der Datenbank an, da der Haskell-Compiler das Projekt andernfalls nicht übersetzt.

Listing 2

MySQL-Datenbank in Betrieb nehmen

01 mysql -u root -h localhost -p
02 mysql> CREATE DATABASE mydb;
03 mysql> CREATE USER 'user'@'localhost' IDENTIFIED BY 'password';
04 mysql> GRANT ALL PRIVILEGES ON mydb.* TO 'user'@'hostname' IDENTIFIED BY 'password';

Wer für sein Projekt eine PostgreSQL-Datenbank nutzen möchte, startet über die Schritte aus Listing 3. Wer keine hohen Ansprüche an die Datenbank stellt, greift am besten zu SQlite [12], das für nur einen Benutzer gedacht ist. Yesod erzeugt sie im Projektordner, was die Datenbank sofort einsatzfähig macht.

Listing 3

PostgreSQL-Datenbank aufsetzen

01 systemctl start Datenbank
02 psql -U postgres -c "CREATE EXTENSION adminpack;"
03 postgres=# CREATE USER 'user' WITH PASSWORD 'password';
04 postgres=# CREATE DATABASE myproject;
05 postgres=# GRANT ALL PRIVILEGES ON DATABASE myproject TO 'user';
06 postgres=# \q

Erstkontakt

Die zum Kompilieren des Projekts benötigten Pakete schreibt Stack in die Datei »stack.yaml«. Dabei wählt das Tool automatisch den neuesten Snapshot des Haskell-Compilers. Das lässt sich über den Eintrag neben »resolver:« ändern, unter [13] sucht der Entwickler einen Snapshot aus. Alternativ gibt er die Versionsnummer eines systemweit installierten Haskell-Compilers an, will er diesen einspannen.

Hat er die Datei »stack.yaml« bearbeitet, lädt der Entwickler mit »stack build« die geforderten Pakete herunter und installiert sie lokal. Anschließend startet er das Projekt mit dem Befehl »stack exec — yesod devel« im Entwicklermodus. Sofern er am Domainnamen nichts geändert hat, ruft er die zugehörige Webseite im Browser seiner Wahl über »http://localhost:3000« auf (Abbildung 1).

Abbildung 1: Der Entwicklermodus bringt bereits einen integrierten Webserver mit. Die Webseite erreicht der Nutzer, indem er als URL [https://localhost:3000] in den Browser tippt.

Abbildung 1: Der Entwicklermodus bringt bereits einen integrierten Webserver mit. Die Webseite erreicht der Nutzer, indem er als URL [https://localhost:3000] in den Browser tippt.

Für eine erste Demonstration genügt es, eine allein stehende Datei namens »contact.hs« anzulegen und sie mit dem Inhalt aus Listing 4 zu füllen. Das lehnt sich an ein Beispiel von Yesod-Erfinder Michael Snoyman an [14] und erzeugt ein einfaches Kontaktformular. Da es in nur einer Datei steckt, erspart dies eine Projektinitialisierung mit Stack. Die einfache Webanwendung ruft dann ein schlichter Stack-Befehl auf:

Listing 4

contact.hs

01 -- in geschweiften Klammern stehen Quasi Quotes
02 {-# LANGUAGE ViewPatterns #-}
03 {-# LANGUAGE MultiParamTypeClasses #-}
04 {-# LANGUAGE OverloadedStrings     #-}
05 {-# LANGUAGE TypeFamilies          #-}
06 {-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
07 -- Bibliotheken importieren
08 import Yesod
09 import Data.Text
10 import Control.Applicative
11 import Yesod.Form
12 -- setzt den Port des Webservers Warp auf 3000
13 main :: IO ()
14 main = warp 3000 FormApp
15 data FormApp = FormApp
16 instance Yesod FormApp
17 instance RenderMessage FormApp FormMessage where
18     renderMessage _ _ = defaultFormMessage
19 -- die Webanwendung "FormApp" bringt nur eine Route mit
20 mkYesod "FormApp" [parseRoutes|
21 /contact  ContactR GET |]
22 -- eine Hilfsfunktion bindet das Formular widget in eine Webseite ein
23 page enctype widget res = defaultLayout $ do
24 -- Titel der Webseite setzen
25         setTitle "Contact"
26         [whamlet|
27                 <p>Ergebnis: #{show res}
28                 <form enctype=#{enctype}>
29                         ^{widget}
30                         <button>Senden
31     |]
32 -- Datentypen der HTML-Eingabefelder
33 data ContactForm = ContactForm {
34      contactName ::  Text
35     ,contactEmail :: Text
36     ,contactText :: Textarea
37 } deriving Show
38 -- Funktion erzeugt ein Formular vom Typ MForm
39 createForm ::  Html -> MForm Handler (FormResult ContactForm, Widget)
40 createForm extra = do
41 -- mreq = required -> Pflichtfeld
42         (nameRes,nameView) <- mreq textField "Name" Nothing
43         (emailRes,mailView) <- mreq emailField  "Email" Nothing
44         (textRes,textView) <- mreq textareaField "Text" Nothing
45         let contactRes = ContactForm <$> nameRes <*> emailRes <*> textRes
46             widget = do
47             toWidget
48 -- Lucius-Stylesheet einbinden
49                 [lucius|
50                     @bColor: mediumseagreen;
51                     ##{fvId nameView}, ##{fvId mailView}, ##{fvId textView}{
52                         border: 3px solid #{bColor};
53                     }
54                 |]
55             [whamlet|
56                 #{extra}
57                 <h1>Kontaktformular!
58                 <p>Name: ^{fvInput nameView}
59                 <p>Email: ^{fvInput mailView}
60                 <p>Text: ^{fvInput textView}
61             |]
62         return (contactRes,widget)
63 getContactR :: Handler Html
64 getContactR = do
65    ((res,widget), enctype) <- runFormGet $ createForm
66    page enctype widget res

stack runghc /Pfad/zu/contact.hs

Der Code in Listing 4 fragt den Besucher der Seite nach seinem Namen und seiner E-Mail-Adresse und fordert ihn dazu auf, eine Nachricht zu hinterlassen (Abbildung 2). Ruft er die Webseite auf, erzeugt die Funktion »getContactR« das Formular, ein Klick auf »Senden« gibt die zuvor übermittelten Daten aus.

Abbildung 2: Mit einer Seite Code l&auml;sst sich das Kontaktformular realisieren, dazu braucht es kein aufw&auml;ndiges Projekt.

Abbildung 2: Mit einer Seite Code lässt sich das Kontaktformular realisieren, dazu braucht es kein aufwändiges Projekt.

Yesods Ökosystem

Die folgenden Listings sind Ausschnitte aus dem Projektordner, den Stack erzeugt, sobald der Entwickler »stack new Meinprojekt« aufruft. Das Originalprojekt besteht im Wesentlichen aus den Seiten, die die Abbildungen 1, 4 und 5 zeigen. Dort gibt es ein Login sowie einen Link auf Dokumente zu Yesod und die Möglichkeit, Dateien hochzuladen. Außerdem beinhaltet die Startseite eine kurze Einführung ins Framework.

Abbildung 3: Dieses Anmeldefenster erscheint, wenn der Anwender auf der Startseite des Projekts auf <code>Login</code> klickt.

Abbildung 3: Dieses Anmeldefenster erscheint, wenn der Anwender auf der Startseite des Projekts auf »Login« klickt.

Das Beispielprojekt überschreibt das Login mit der Option, sich per Google und Yahoo anzumelden (Abbildung 3), und setzt die maximale Anzahl an hochladbaren Dateien auf 1 (Abbildung 4).

Für den Schnelleinstieg in Yesod will der Entwickler gewöhnlich auch wissen, welche Informationen wohin gehören. Eine Übersicht der wichtigsten Dateien liefert Tabelle 1.

Tabelle 1

Ordner “Meinprojekt” im Überblick

Ordner/Dateiname

Inhalt

»Application.hs«

Anwendung initialisieren, Handler eintragen

»Foundation.hs«

Plugins konfigurieren

»Projektname.cabal«

Erweiterungen, Pakete und Handler eintragen

»stack.yaml«

Pakete, GHC-Compiler

»config/settings.yml«

Globale Variablen

»config/favicon.ico«

Icon

»config/models«

Datenbankschema

»config/routes«

Routen

»Handler/handler.hs«

Handler

»static/«

CSS, Javascript, Bilder, Fonts

»templates/«

Vorlagen in Hamlet, Julius, Cassius oder Lucius

Nun kann der Entwickler Dateien bearbeiten. Ein individuelles Icon für die URL-Leiste definiert er zum Beispiel, indem er die Datei »config/favicon.ico« durch eine gleichnamige Eigenkomposition ersetzt. In der Datei »config/models« wartet ein Datenbankschema, das er beliebig anpasst. Die Änderungen wirken sich dabei auf das laufende System aus, sobald der Entwickler sie speichert – er muss die Webanwendung dafür nicht neu starten. Das gilt auch für Änderungen an anderen Dateien des Projekts.

Abbildung 4: Im Formularteil der leicht ver&auml;nderten Webseite zeigt eine Variable nun die Zahl der maximal hochladbaren Dateien an.

Abbildung 4: Im Formularteil der leicht veränderten Webseite zeigt eine Variable nun die Zahl der maximal hochladbaren Dateien an.

In der Datei »config/routes« legt er dann die Routen fest, also die URLs, über die Nutzer die einzelnen Webseiten erreichen. Dabei darf er POST-, GET- und andere Methoden pro Route in derselben Datei speichern.

Abbildung 5: Im letzten Teil der Startseite hinterlassen Anwender entweder einen Kommentar oder informieren sich &uuml;ber das Testen von Software unter Yesod.

Abbildung 5: Im letzten Teil der Startseite hinterlassen Anwender entweder einen Kommentar oder informieren sich über das Testen von Software unter Yesod.

Pro Route verlangt Yesod außerdem nach einem Handler. Der bestimmt, was geschieht, sobald ein User eine Route aufruft. Neue Handler erstellt der Entwickler am besten im Ordner »Handler«, wobei er beachten sollte, die Haskell-typische Endung ».hs« zu verwenden. Nicht zuletzt bestimmt er in der Datei »config/settings.yml« unter dem Stichwort »APPROOT« den Namen der Domain, auf der das Yesod-Framework läuft.

In den Unterordner »static« gehören Javascript-Dateien, Stylesheets, Schriftarten und Bilder. Erwähnenswert ist in diesem Zusammenhang, dass das Projekt das weit verbreitete CSS-Framework Bootstrap [15] im Gepäck hat. Dabei gehören in den »static«-Ordner nur reine CSS- oder Javascript-Dateien. Der Grund: Yesod besitzt eine eigene Template-Sprache, die damit erstellten Dateien befinden sich üblicherweise im »templates«-Verzeichnis.

Im Unterordner »Meinprojekt/test« wartet Beispielcode, mit dem Entwickler die Webanwendung auf Herz und Nieren prüfen. Darüber hinaus existieren mehrere erwähnenswerte Dateien im Hauptordner des Projekts. So initialisiert Yesod globale Variablen oder Datentypen in der Datei »Application.hs« (Listing 6), auf deren Werte der Handler (Listing 8) über die Funktion »getYesod« zugreift.

Soll beispielsweise ein Anwender der Webseite maximal fünf Bilder pro Ticket hochladen dürfen, importiert der Entwickler hierzu eine eigene Datei (Listing 5), in der er einen Datentyp zusammen mit einer Funktion, die die Variable initialisiert, festgelegt hat.

Listing 5

<I>Meinprojekt<I>/Model/MySettings.hs

01 module Model.MySettings
02     (
03           MySettings(..)
04         , newSettings
05     )where
06 import [...]
07 -- Typsynonym
08 type Max = Int
09 --Datentyp MySettings
10 data MySettings = MySettings
11     { myMax         :: Max }
12 --diese Funktion legt die maximale Anzahl an hochladbaren Dateien fest
13 newSettings num = do
14   return MySettings { myMax = num }

Anschließend deklariert er in der »makeFoundation«-Funktion (Listing 6) eine lokale Variable, die die maximale Anzahl an hochladbaren Dateien enthält, und übergibt diese Variable der importierten Funktion, welche die Variable initialisiert. Zusätzlich legt er fest, welche Datentypen zur Webanwendung namens App gehören (Listing 7).

Listing 6

<I>Meinprojekt<I>/Application.hs

01 [...]
02 import Model.MySettings
03 [...]
04 makeFoundation :: AppSettings -> IO App
05 makeFoundation appSettings = do
06     [...]
07     -- maximale Anzahl an hochladbaren Dateien
08     let maxFiles = 5
09     mysettings' <- newSettings maxFiles
10     --Variable "myMax" global verfügbar machen
11         let mkFoundation appConnPool = App mysettings'
12 [...]

Sein oder nicht sein

Für die Namen der Template-Sprache muss Shakespeare herhalten. So heißt die Sprache, mit der Yesod aus einer Vorlage HTML-Dateien erzeugt: Hamlet. Wer HTML kennt, dürfte sich schnell in Hamlet einarbeiten. Zusätzlich erlaubt Hamlet Wenn-dann-Abfragen und Fallunterscheidungen über Case und Maybe sowie außerdem Schleifen.

Listing 7

<I>Meinprojekt<I>/Foundation.hs (Auszug 1)

01 [...]
02 import Model.MySettings
03 [...]
04 --Name der Webanwendung = App
05 data App = App
06     -- In der App tauchen nur die Variablen des Datentyps MySettings auf.
07     -- Unter Java könnte der Entwickler MySettings mit einer Klasse vergleichen,
08     -- die die Variable myApp besitzt. Diese ist vom Typ MySettings.
09     {mySettings    :: MySettings }
10 [...]

Daneben existieren die beiden Stylesheet-Sprachen Cassius und Lucius, mit denen der Entwickler bei Bedarf die Einstellungen im globalen Stylesheet überschreibt. Während Lucius genauso wie CSS bei Definitionen der einzelnen Selektoren Wert auf Klammern legt und am Ende eines Statements ein Semikolon verlangt, kommt Cassius gänzlich ohne diesen Mehraufwand aus. Bei dieser Stylesheet-Sprache sollte der Entwickler allerdings die Definition eines Selektors einrücken.

Listing 8

<I>Meinprojekt<I>/Handler/Home.hs (Auszug 1)

01 [...]
02 module Handler.Home where
03 [...]
04 -- Handler, der die Seite www.domainname erstellt
05 getHomeR :: Handler Html
06 getHomeR = do
07 [...]
08 -- mit getYesod auf globale Variablen zugreifen
09         (App{mySettings=s}) <- getYesod
10      let (M.MySettings {M.maxFiles=m }) = s
11 [...]

Im Gegensatz zu CSS lassen sich unter Lucius oder Cassius Variablen definieren, was Codezeilen einspart. Mit Hilfe von Julius erstellt der Entwickler Javascript-Dateien, die ebenfalls auf Variablen zugreifen, die im Projekt existieren. So verwendet er die Namen der Routen in einer Julius-Datei. Bereits vorhandene CSS-Stylesheets oder Javascript-Dateien bindet er statisch ein, ohne sie in ein anderes Format übertragen zu müssen. In Listing 9 lädt Yesod das Stylesheet »static/css/styling.css«, sobald der User eine beliebige Route aufruft.

Listing 9

<I>Meinprojekt<I>/Foundation.hs (Auszug 2)

01 [...]
02 -- definiert das Standardlayout, das für jede Seite einer bestimmten Domain gilt
03 pc <- widgetToPageContent $ do
04             addStylesheet $ StaticR css_styling_css
05 -- die Vorlage des Standardlayouts steht in der Datei "default-layout.hamlet"
06             $(widgetFile "default-layout")
07         withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
08 [...]

Bei neuen Dateien empfiehlt es sich hingegen, die Template-Sprachen zu verwenden. Soll zum Beispiel der Handler, der die Homepage realisiert, zusätzlich HTML-Code in eine Hamlet-Datei, ein passendes Stylesheet sowie eine Julius-Datei einbinden, sollte der Entwickler darauf achten, dass die Namen dieser Dateien alle gleich lauten, zum Beispiel »homepage.hamlet«, »homepage.julius« und »homepage.lucius«. Auf diese Weise muss er nur einmal eine Datei in den Handler integrieren und es genügt, im Handler auf »homepage« Bezug zu nehmen (Listing 10). Yesod lädt die Vorlagen dann automatisch.

Listing 10

<I>Meinprojekt<I>/Handler/Home.hs (Auszug 2)

01 [...]
02 module Handler.Home where
03 [...]
04 -- Handler, der die Homepage einer Domain erzeugt
05 -- In der Datei homepage.hamlet befindet sich die Vorlage zur Homepage
06 getHomeR :: Handler Html
07 getHomeR = defaultLayout $(widgetFile "homepage")
08 [...]

Sicherheit gewährleisten

Soll ein Anwender den Webmaster über ein Kontaktformular kontaktieren, erzeugt der Entwickler unter Yesod die nötigen Formulare, ohne etliche Zeilen an Code zu schreiben. Zwei unterschiedliche Methoden versprechen das gleiche Ergebnis. Wer einfach loslegen will, für den eignen sich Formulare vom Typ A-Form. Für sie braucht der Entwickler keine zusätzliche Hamlet-Datei, sondern es genügt, wenn er wie in der Funktion »contactAForm« (Listing 11) angibt, aus welchen HTML-Feldern das Formular bestehen soll.

Listing 11

contact-v2.hs

01 [...]
02 data ContactForm = ContactForm {
03      contactName ::  Text
04     ,contactEmail :: Text
05     ,contactText :: Textarea
06 } deriving Show
07
08 -- erzeugt ein Formular vom Typ A-Form
09 contactAForm :: AForm Handler ContactForm
10 contactAForm = ContactForm
11     <$> areq textField "Name"  Nothing
12     <*> areq textField  "Email"   (Just "info@example.com")
13     <*> areq textareaField "Text"  Nothing
14
15 contactForm :: Html -> MForm Handler (FormResult ContactForm, Widget)
16 contactForm = renderBootstrap2 contactAForm
17
18 getContactR = do
19    (widget, enctype) <- generateFormPost $  contactForm
20    page enctype widget
21 [...]

Daneben existieren die weiter oben erwähnten monadischen Formulare vom Typ M-Form, deren Aussehen der Entwickler selbst bestimmen darf (Abbildung 2.) Allerdings muss er dafür die zuvor definierten HTML-Eingabe-Elemente in den Hamlet-Abschnitt einfügen. In die Hamlet-Dateien trägt er außerdem Klassen oder IDs ein, die er zuvor in Lucius oder Cassius definiert hat (vergleiche dazu Listing 4).

Die Sicherheit gewährleistet Yesod mit Hilfe von Sicherheits-Token, die es in einem versteckten HTML-Eingabefeld speichert. Diese Token verhindern so genannte Cross-Site-Request-Forgery-Angriffe. Der Entwickler braucht bei Formularen vom Typ M-Form nur die Variable »#{extra}« im Hamlet-Abschnitt einzutragen. Bei Formularen vom Typ A-Form fügt Yesod hingegen die Extravariable automatisch hinzu.

Schlauer Compiler

Kommen die Anwendereingaben beim Server an, überprüft Yesod diese auf Javascript-Injections hin, indem es die Daten nach Javascript-Befehlen wie zum Beispiel »<script> […]</script>« untersucht und diese entschärft. So ersetzt Yesod etwa ein »<« durch ein »&lt«. Nach diesem Prinzip schützt Yesod die Datenbank auch vor SQL-Injections [16].

Der Haskell-Compiler prüft beim Übersetzen den Typ der Funktion, was Typverletzungen bereits im Vorfeld verhindert. Darüber hinaus checkt er die Vorlagen, die der Entwickler mit einer Vorlagensprache aus der Shakespeare-Familie erschaffen hat, auf Syntaxfehler. Somit kommt es während des Betriebs nicht zu Überraschungen.

Kekse

Zwar handelt es sich bei Yesod um eine Restful-Application, aber mitunter muss das Framework beim Interagieren mit Clients auch Sitzungsdaten speichern, etwa beim Einsatz von Einkaufswagen. Das Paket »clientsession« nutzt Verschlüsselung und Signaturen, um Daten in Cookies bereitzustellen. Das stellt einerseits sicher, dass der User nicht mit den Daten spielt, zum anderen verhindert die Signatur MITM-Angriffe.

Listing 12

<I>Meinprojekt<I>/Foundation.hs (Auszug 3)

01 [...]
02 instance Yesod App where
03     makeSessionBackend _ = Just <$> defaultClientSessionBackend
04         -- timeout in Minuten
05         120
06         "Pfad/zum/Cookie.aes"

Der Entwickler legt fest, wie lange ein Cookie gültig ist. Um die Cookies zu nutzen, trägt er in der Datei »Foundation.hs« ein, wo auf dem Server Yesod das Cookie ablegt. Listing 12 zeigt ein solches Session-Cookie. Firefox akzeptiert solche Cookies sogar im privaten Modus (Abbildung 6), sodass der Entwickler nicht darauf zu verzichten braucht. Cookies verstecken zudem sensible Daten, welche die URL betreffen.

Abbildung 6: Firefox zeigt den verschl&uuml;sselten Inhalt eines Cookie an. Normalerweise sind die von Yesod erzeugten Cookies zwei Stunden lang g&uuml;ltig.

Abbildung 6: Firefox zeigt den verschlüsselten Inhalt eines Cookie an. Normalerweise sind die von Yesod erzeugten Cookies zwei Stunden lang gültig.

Code recyceln

Modularität bezeichnet unter anderem die Wiederverwendbarkeit von Code in anderen Projekten. Das lässt sich unter Yesod mit Hilfe von Unterseiten, den so genannten Subsites, umsetzen. Diese Subsites sind selbst eigenständige Programme, zum Beispiel eine Chat-Anwendung, die in mehreren Softwareprojekten vorkommen. Der Entwickler braucht dazu nur den Ordner mit der Subsite ins neue Projekt zu kopieren.

Listing 13

<I>Meinprojekt<I>/Googleemail.hs

01 module Googleemail where
02 import Data.Text
03
04 clientId :: Text
05 clientId = "myid"
06
07 clientSecret :: Text
08 clientSecret = "mysecret"

Zur Umsetzung von Subsites sei erwähnt, dass zwar einige Beispiele in dem Buch von Michael Snoyman existieren, aber im Web wenig Brauchbares vorhanden ist. Entwickler müssten sich demnach vieles selbst beibringen oder aus verschiedenen Quellen zusammensuchen.

Listing 14

<I>Meinprojekt<I>/Foundation.hs (Auszug 4)

01 [...]
02 import Yesod.Auth.OpenId
03 import Yesod.Auth.GoogleEmail2
04 import Googleemail
05 [...]
06 instance YesodAuth App where
07           authPlugins m =
08                         [ authGoogleEmail clientId clientSecret ]
09
10     [...]
11     -- Standardwert: Authorized
12     isAuthorized _ _ = return Authorized
13     [...]

Ein weiteres Beispiel für Modularität unter Yesod sind Haskell-Programme oder Haskell-Module. So lässt sich ein in Haskell geschriebenes Spiel in ein Yesod-Projekt importieren, auf das der Anwender über den Browser zugreift.

Authentifizierung erforderlich

Um die Benutzerkonten der Anwender zu schützen, stellt Yesod Bibliotheken zur Verfügung, mit denen der Entwickler die Anmeldung umsetzt. Dazu gehört die Bibliothek Yesod.Auth.OpenId [17], die es Anwendern ermöglicht, sich über ein bestehendes Google-Plus- oder Yahoo-Konto auf der Webseite einzuloggen, ohne dass der Webmaster die Passwörter verwalten muss. Um diese Authentifizierung zu implementieren, muss die Foundation-Datei die oben genannte Bibliothek importieren. Der Entwickler aktiviert das Plugin und gibt zudem an, welche Routen keine Authentifizierung oder Anmeldung brauchen (Listing 15).

Listing 15

<I>Meinprojekt<I>/Foundation.hs (Auszug 5)

01 [...]
02 instance YesodAuth App where
03         loginHandler = defaultLayout $ do
04             [whamlet|
05                 <form method="get" action=@{AuthR forwardUrl} >
06                     <input type="hidden" name="openid_identifier" value="https://www.google.com/accounts/o8/id">
07                     <button class="btn-openid">
08                         <span>Login via Google
09            |]
10  [...]

Mitunter gilt es, auch in der Projektdatei »Projektname.cabal« Bibliotheken einzutragen, damit Yesod das Projekt erfolgreich übersetzt. Darauf weist das Framework den Entwickler beim Kompilieren des Projekts noch einmal hin.

Indem er den Login-Handler in der Foundation-Datei überschreibt (Listing 15), gestaltet der Entwickler die Anmeldeseite nach seinen Wünschen. In Yesod genügt einfacher HTML-Code, um den Login-Handler umsetzen.

Fazit

Die Performance von Haskell, auf das Yesod ja setzt, ist gut genug, um das Herzstück des Sigma-Systems von Facebook zu bilden. Facebook verwendet Haskell unter anderem zur Spam-Abwehr, das dort eingesetzte Produktionssystem verarbeitet rund eine Million Anfragen pro Sekunde [18].

Zumindest nach projekteigener Messung [19] mit einer großen Amazon-EC2-Instanz gehört auch das Haskell-basierte Yesod zu den schnellsten Webframeworks. Zusätzlich bietet es alles, um auch größer angelegte Projekte anzugehen, unterstützt es doch zum Beispiel eine Reihe bekannter Datenbanken.

Doch während es für Bezahlsysteme wie Paypal etliche Anleitungen für die Programmiersprachen Java und PHP gibt, sind hilfreiche Hinweise für Yesod beziehungsweise Haskell rar gesät. Eine Erweiterungsvielfalt, wie sie etwa Drupal und WordPress mit einer fünfstelligen Zahl an Plugins bieten, sucht der Yesod-Nutzer vergeblich.

Zudem stellt die Haskell-Basis trotz zahlreicher Erleichterungen auch das Durchhaltevermögen des Entwicklers auf die Probe. Er kann beispielsweise Fehlermeldungen des Compilers nicht immer leicht entziffern. Dennoch: Unter den Haskell-basierten Web-Frameworks gehört Yesod zu den fortgeschrittensten.

Dazu tragen vor allem die eigenen Template-Sprachen sowie zahlreiche Bibliotheken bei. Zudem bietet Yesod neugierigen Entwicklern neben den anfangs erwähnten Vorteilen einen Anreiz, am praktischen Beispiel in die Haskell-Welt einzutauchen.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 7 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben