Photo by Aidas Ciziunas, Unsplash.com

Photo by Aidas Ciziunas, Unsplash.com

Haskell framework for the web

Speaking in Tongues

Article from ADMIN 42/2017
By
The Yesod web framework includes a Haskell compiler on top of the standard web technologies, such as HTML, JavaScript, and CSS, with aggressive optimization and function checks for correctness.

Frameworks for the web are a dime a dozen. Most are based on the PHP and JavaScript programming languages, whereas others use Python, Ruby, Go, or other such languages. When a developer uses WordPress [1], Drupal [2], or Joomla [3], generally they only have to unpack the core on the server and then add other modules. Installing security updates conscientiously and in good time counteracts ubiquitous malware threats.

Quite a few reasons speak to the use of exotic frameworks such as the Haskell-based Yesod [4] [5]. It is not just that Yesod is less widespread, it is also that the security built into the compiler (Haskell is type safe) makes attacks time-consuming or impossible, and SQL and JavaScript injections unlikely. Additionally, the Glasgow Haskell Compiler (GHC) [6], version 1.0 of which has existed since April 1990, is based on the fast C compiler and processes requests to the website far more efficiently than many other programming languages. Because Haskell is a functional programming language, it facilitates other tasks, such as multithreading.

Developers mainly ask themselves one question: How do I get started with the framework? Haskell is considered difficult to learn, because it is strongly orientated on mathematical logic and uses many abstract concepts like monads and category theory. A framework like Yesod helps developers make the transition to Haskell and levels a still steep learning curve, thanks to pre-built components that promise quick results. In this article, I will help you take your first steps with Yesod.

Installation

Stack [7] is available to help you install the framework and set up a software project. The process differs from one operating system to the next, but this article describes its use on Fedora 25, which first needs a couple of packages from the unofficial repository [8] to make Stack operational (Listing 1). To start a new Yesod project, just install the Haskell compiler locally:

cd
stack setup

Listing 1

Stack on Fedora 25

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

After the install, the Haskell compiler is located under ~/.stack/programs/x86_64-linux/<GHC version>/bin. Additional packages that a Yesod project might require can be installed with the simple stack install <package name>, as needed.

Home Base

Once you have overcome the first hurdle, the real work begins. Yesod supports various popular databases, including MongoDB, SQLite, and, to some extent, Redis. Here, I describe the integration of PostgreSQL [9] and MySQL [10]. To begin, create a new project by entering the command:

stack new <project name> yesod-<database>

Replace <database> with a valid value, which you can take from a table online [11] (e.g., postgres or mysql).

If you want the web application to load data into a MySQL database, the database must be running in the background beforehand (Listing 2). Next, change to the project directory generated by Stack and edit the config/settings.yml file. Under the database: heading, adjust the entries for the database user, host, and the name of the database, because otherwise the Haskell compiler will not compile the project.

Listing 2

Setting Up the MySQL DB

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

If you want to use a PostgreSQL database for your project, start with the steps in Listing 3. If you do not have high demands on the database, your best database option is SQLite [12], which is intended for a single user only. Yesod creates the database in the project folder, which means that the database is ready for use immediately.

Listing 3

Setting Up the PostgreSQL DB

systemctl start <database>
psql -U postgres -c "CREATE EXTENSION adminpack;"
postgres=# CREATE USER '<user>' WITH PASSWORD '<password>';
postgres=# CREATE DATABASE <myproject>;
postgres=# GRANT ALL PRIVILEGES ON DATABASE <myproject> TO '<user>';
postgres=# \q

First Contact

Stack writes the packages required for compiling the project to the stack.yaml file. The tool automatically selects the latest snapshot of the Haskell compiler, which can be changed using the entry next to resolver:; you can choose a snapshot from the Stackage Snapshots page [13]. Alternatively, you can specify the version number of a globally installed Haskell compiler you want to use.

Once you have processed the stack.yaml file, you can download the required packages with stack build and install them locally. Next, launch the project in developer mode with the

stack exec --yesod devel

command. Provided you have not changed the domain name, you can call the associated web page in the browser of your choice with http://localhost:3000 (Figure 1).

Figure 1: Developer mode comes with an integrated web server. Users reach the website by typing https://localhost:3000 in their browsers.

For a first demonstration, you just need to create a single file called contact.hs and fill it with the Listing 4 content, which is based on an example from Yesod inventor Michael Snoyman [14] and generates a simple contact form. Being just one file removes the need for project initialization with Stack. The simple web application then calls a simple Stack command:

stack runghc /<Path/to>/contact.hs

Listing 4

contact.hs

01 -- Quasi quotes in curly brackets
02 {-# LANGUAGE ViewPatterns #-}
03 {-# LANGUAGE MultiParamTypeClasses #-}
04 {-# LANGUAGE OverloadedStrings     #-}
05 {-# LANGUAGE TypeFamilies          #-}
06 {-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
07 -- import libraries
08 import Yesod
09 import Data.Text
10 import Control.Applicative
11 import Yesod.Form
12 - set the web server port Warp to 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 - the "FormApp" web application only provides one route
20 mkYesod "FormApp" [parseRoutes|
21 /contact  ContactR GET |]
22 - an auxiliary function integrates the form widget into a web page
23 page enctype widget res = defaultLayout $ do
24 -- set the title of the website
25         setTitle "Contact"
26         [whamlet|
27                 <p>Result: #{show res}
28                 <form enctype=#{enctype}>
29                         ^{widget}
30                         <button>Send
31     |]
32 - HTML input field data types
33 data ContactForm = ContactForm {
34      contactName ::  Text
35     ,contactEmail :: Text
36     ,contactText :: Textarea
37 } deriving Show
38 - function generates a form of MForm type
39 createForm ::  Html -> MForm Handler (FormResult ContactForm, Widget)
40 createForm extra = do
41 -- mreq = required -> required field
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 -- integrate Lucius stylesheet
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>Contact Form!
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

The code in Listing 4 asks site visitors for their names and email addresses and prompts them to leave a message (Figure 2). When you access the web page, the getContactR function (lines 63 and 64) generates the form, and clicking on Send outputs the previously submitted data.

Figure 2: The contact form can be implemented in a single page and is not a complex project.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Lua for Apache

    Lua is a small, lean, and fast scripting language – ideal for working with web servers. Version 2.4 of the Apache web server is the first to offer a matching module that has a few quirks – and pitfalls, if you dig more deeply.

  • How to Hide a Malicious File

    The best way to stop an attack is to think like an attacker. We’ll show you how to use the Metasploit framework to create a malicious payload that escapes antivirus detection.

  • A DIY HTML Engine
    Jekyll is a lightweight, fast, HTML engine that renders websites with ease, with the added benefits of low cost, high speed, security, and free hosting with GitHub Pages.
  • Slipping your pen test past antivirus protection with Veil-Evasion
    The Veil pen-testing platform provides some powerful tools that will hide your attack from antivirus scanners – and Veil even supports Metasploit payloads.
  • Introduction to HDF5

    HDF5 is a data model, library, and file format used primarily for scientific computing to store and manage data.

comments powered by Disqus