vidéo peertube - vidéo youtube - dépôt git
Développement web en Haskell
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 ()
main = scotty 3000 $ do -- crée un serveur web sur le port 3000
-- paramétrage du serveur
middleware logStdoutDev
middleware simpleCors
-- route racine "/"
get "/" $ html "<html><body><a href='page2'>page2</a></body></html>"
-- route "/page2"
get "/page2" $ html "hello"
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
fromRow = Task <$> field <*> field
-- nom du fichier contenant la base sqlite
dbName :: String
dbName = "todolist.db"
- requêtes SQL :
selectTasks :: IO [Task]
selectTasks =
SQL.withConnection dbName (\c -> SQL.query_ c "SELECT * FROM task")
-- ...
- utilisation dans le programme principal :
main :: IO ()
main = scotty 3000 $ do
-- ...
get "/" $ do -- route racine
myTasks <- liftIO selectTasks -- accède à la base de données
html $ renderHome myTasks -- calcule la page résultat
-- ...
Export JSON
Bibliothèque aeson.
- export de notre type de données :
- utilisation dans le programme principal :
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
bodyCss = C.body C.? do
C.backgroundColor C.beige
divCss :: C.Css
divCss = C.div C.? do
C.border C.solid (C.px 1) C.black
C.backgroundColor C.azure
- génération de code HTML :
renderHome :: [Task] -> L.Text
renderHome theTasks = renderText $ do
doctype_
html_ $ do
header_ $ style_ $ L.toStrict $ C.render $ do
bodyCss
divCss
body_ $ do
h1_ "TODO list"
div_ $ ul_ $ mapM_ formatTask theTasks
form_ [action_ "/add", method_ "post"] $ do
p_ $ do
"New task: "
input_ [name_ "task_name"]
input_ [type_ "submit"]
p_ $ a_ [href_ "tasks"] "Get JSON data"
where formatTask :: Task -> Lucid.Html ()
formatTask (Task tId tName) =
li_ $ do
toHtml tName
" - "
a_ [href_ (T.concat ["del?task_id=", T.pack $ show tId])] "delete"
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)…