Déployer une application Haskell/PostgreSQL sur Heroku

Voir aussi : vidéo peertube - vidéo youtube - dépôt git

Heroku est un service de cloud de type PaaS (Platform as a Service), comme Amazon Web Service, Google App Engine, Microsoft Azure, Red Hat OpenShift… Heroku propose une offre gratuite, limitée mais suffisante pour déployer des applications web simples.

Ce tutoriel montre comment écrire, configurer et déployer, sur Heroku, une application web en Haskell avec une base de données PostgreSQL.

Application Haskell/PostgreSQL, dans un dépôt git

SELECT current_database();
SELECT current_user;

CREATE TABLE artists (
  id INTEGER PRIMARY KEY,
  name TEXT
);
INSERT INTO artists VALUES(0, 'Radiohead');
-- ...

CREATE TABLE titles (
  id INTEGER PRIMARY KEY,
  artist INTEGER,
  name TEXT,
  FOREIGN KEY(artist) REFERENCES artists(id)
);
INSERT INTO titles VALUES(0, 0, 'Paranoid android');
-- ...
{-# LANGUAGE OverloadedStrings #-}

import qualified Data.Text as T
import qualified Data.Text.Lazy as L
import System.Environment (getEnv)
import Web.Scotty (get, html, scotty)

import Control.Monad.Trans (liftIO)
import qualified Data.ByteString.Char8 as B8
import qualified Database.PostgreSQL.Simple as P

type DbTitle = (T.Text, T.Text)

formatTitles :: [DbTitle] -> T.Text
formatTitles = T.intercalate "<br/>\n" . map (\ (a, t) -> T.concat [a, " - ", t]) 

getMusic :: String -> IO T.Text
getMusic params = do
    conn <- P.connectPostgreSQL $ B8.pack params
    titles <- P.query_ conn "SELECT artists.name, titles.name FROM artists \
                            \ INNER JOIN titles ON artists.id = titles.artist" :: IO [DbTitle]
    P.close conn
    return $ formatTitles titles

main :: IO ()
main = do
    dbParams <- getEnv "DATABASE_URL"
    portStr <- getEnv "PORT"
    let port = read portStr

    scotty port $ do
        get "/" $ do
            music <- liftIO $ getMusic dbParams
            html $ L.fromStrict $ music
name:               heroku-musicapp
version:            0.1
license:            BSD3
build-type:         Simple
cabal-version:      >=1.10

executable heroku-musicapp
  main-is:            Main.hs
  default-language:   Haskell2010
  build-depends:      base, bytestring, mtl, postgresql-simple, scotty, text
resolver: lts-11.15

Installer les clients Heroku et PostgreSQL

nix-env -iA nixos.heroku
nix-env -iA nixos.nodejs-8_x nixos.nodePackages.node2nix nixos.postgresql100

git clone https://github.com/heroku/cli.git heroku-cli
cd heroku-cli
git checkout 3b5eb335cf35163cf4b3abdc9526a3428eadbc1c
node2nix -8
nix-build -A package
nix-env -i ./result

Déployer sur Heroku

web: heroku-musicapp 
heroku login
heroku create --buildpack https://github.com/mfine/heroku-buildpack-stack.git
git push heroku master
heroku addons:create heroku-postgresql:hobby-dev
heroku psql -f music.sql
heroku logs
heroku logout

Portail web d’Heroku

Développement local en utilisant la base distante

Heroku définit les variables d’environnement PORT et DATABASE_URL, que l’on utilise dans l’application développée. Pour exécuter en local, il suffit de définir manuellement ces variables d’environnement. On peut aussi récupérer la configuration d’une base Heroku et l’utiliser pour une application locale :

PORT=3000 DATABASE_URL=`heroku config:get DATABASE_URL` nix-shell --run "cabal run"