Développement web en Haskell
Voir aussi : vidéo peertube - vidéo youtube - dépôt git
Introduction
Haskell est bien adapté au développement web côté-serveur : nombreuses bibliothèques, avantages du typage fort…
Objectif de ce tutoriel : exemple d’application web pour gérer une “TODO list”. Fonctionnalités à mettre en oeuvre :
- serveur web avec routage d’url
- accès à une base de données
- export JSON
- génération dynamique de pages HTML/CSS
Application de base
Serveur web de routage d’url avec la bibliothèque scotty.
Bibliothèques Haskell de frameworks web : frameworks lourds à la “Ruby on Rails” (yesod, snap, hapstack…), frameworks légers à la “Ruby Sinatra” (scotty, spock…).
- programme principal :
main :: IO ()
= scotty 3000 $ do -- crée un serveur web sur le port 3000
main
-- paramétrage du serveur
middleware logStdoutDev
middleware simpleCors
-- route racine "/"
"/" $ html "<html><body><a href='page2'>page2</a></body></html>"
get
-- route "/page2"
"/page2" $ html "hello" get
Base de données
Accès à une base sqlite avec la bibliothèque sqlite-simple.
Bibliothèques Haskell de base de données : bas-niveau (hdbc-odbc…), niveau moyen (sqlite-simple, postgresql-simple…), haut-niveau (persistent, acid-state..).
- modèle pour notre “TODO list” :
-- définit un type de données "Task"
data Task = Task
taskId :: Int
{ taskName :: L.Text
,deriving (Show, Generic) }
- intégration avec une base de données sqlite :
-- définit comment créer une valeur de type Task à partir de données de la base
instance FromRow Task where
= Task <$> field <*> field
fromRow
-- nom du fichier contenant la base sqlite
dbName :: String
= "todolist.db" dbName
- requêtes SQL :
selectTasks :: IO [Task]
=
selectTasks -> SQL.query_ c "SELECT * FROM task")
SQL.withConnection dbName (\c
-- ...
- utilisation dans le programme principal :
main :: IO ()
= scotty 3000 $ do
main -- ...
"/" $ do -- route racine
get <- liftIO selectTasks -- accède à la base de données
myTasks $ renderHome myTasks -- calcule la page résultat
html -- ...
Export JSON
Bibliothèque aeson.
- export de notre type de données :
instance ToJSON Task
- utilisation dans le programme principal :
main :: IO ()
= scotty 3000 $ do
main -- ...
"/tasks" $ liftIO selectTasks >>= json get
Génération de code HTML/CSS
Les bibliothèques lucid et clay fournissent des langages dédiés intégrés (EDSL) pour générer du code HTML et CSS.
- définition de styles CSS :
bodyCss :: C.Css
= C.body C.? do
bodyCss
C.backgroundColor C.beige
divCss :: C.Css
= C.div C.? do
divCss 1) C.black
C.border C.solid (C.px C.backgroundColor C.azure
- génération de code HTML :
renderHome :: [Task] -> L.Text
= renderText $ do
renderHome theTasks
doctype_$ do
html_ $ style_ $ L.toStrict $ C.render $ do
header_
bodyCss
divCss$ do
body_ "TODO list"
h1_ $ ul_ $ mapM_ formatTask theTasks
div_ "/add", method_ "post"] $ do
form_ [action_ $ do
p_ "New task: "
"task_name"]
input_ [name_ "submit"]
input_ [type_ $ a_ [href_ "tasks"] "Get JSON data"
p_ where formatTask :: Task -> Lucid.Html ()
Task tId tName) =
formatTask ($ do
li_
toHtml tName" - "
"del?task_id=", T.pack $ show tId])] "delete" a_ [href_ (T.concat [
Conclusion et perspectives
L’expressivité d’Haskell et ses nombreuses bibliothèques permettent de réaliser des applications web efficacement.
Le système de typage fort permet de détecter de nombreuses erreurs à la compilation.
Autres fonctionnalités à implémenter dans notre application de “TODO list” : authentification, SGBD plus réaliste (mysql, postgresql)…