Web Programming in Haskell
Scotty is a Web framework written in Haskell, which is similar to Ruby’s Sinatra. You can install it on Ubuntu
Using the following commands:
$ sudo apt-get install cabal-install
$ cabal update
$ cabal install scotty
Let us write a simple ‘Hello, World!’ program using the Scotty framework:
— hello-world.hs
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
main :: IO ()
main = scotty 3000 $ do
get “/” $ do
html “Hello, World!”
You can compile and start the server from the terminal using the following command:
$ runghc hello-world.hs
Setting phasers to stun… (port 3000) (ctrl-c to quit)
The service will run on port 3000, and you can open localhost:3000 in a browser to see the ‘Hello, World!’ text. You can then stop the service by pressing Control-C in the terminal. You can also use Curl to make a query to the server.
Use Haskell for Web programming
Install and test it on Ubuntu as shown below:
$ sudo apt-get install curl
$ curl localhost:3000
Hello, World!
You can identify the user client that made the HTTP request to the server by returning the ‘User-Agent’ header value as illustrated in the following example:
— request-header.hs
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
main :: IO ()
main = scotty 3000 $ do
get “/agent” $ do
agent <- header “User-Agent”
maybe (raise “User-Agent header not found!”) text
agent
You can execute the above code in a terminal using the following command:
$ runghc request-header.hs
Setting phasers to stun… (port 3000) (ctrl-c to quit)
If you open the URL localhost:3000/agent in the browser, it returns the following User-Agent information on Ubuntu 14.10: Mozilla/5.0 (X11: Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/41.0.2272.76 Chrome/41.0.2272.76 Safari/537.36. The Curl version is returned for the same URL request as shown below:
$ curl localhost:3000/agent -v
* Hostname was NOT found in DNS cache
* Trying 127.0.0.1…
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /agent HTTP/1.1
> User-Agent: curl/7.37.1
> Host: localhost:3000
> Accept: */*
>
< HTTP/1.1 200 OK
< Transfer-Encoding: chunked
< Date: Wed, 29 Apr 2015 07:46:21 GMT
* Server Warp/3.0.12.1 is not blacklisted
< Server: Warp/3.0.12.1
< Content-Type: text/plain; charset=utf-8
<
* Connection #0 to host localhost left intact
curl/7.37.1
You can also return different content types (HTML, text, JSON) based on the request. For example:
— content-type.hs
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty as W
import Data.Monoid
import Data.Text
import Data.Aeson
main :: IO ()
main = scotty 3000 $ do
get “/hello” $ do
html $ mconcat [“<h1>”, “Hello, World!”, “</h1>”]
get “/hello.txt” $ do
text “Hello, World!”
get “/hello.json” $ do
W.json $ object [“text” .= (“Hello, World!” :: Text)]
You can start the above server in a terminal as follows:
$ runghc content-type.hs
Setting phasers to stun… (port 3000) (ctrl-c to quit)
You can then open the three URLs listed above in a browser to see the different output. The respective outputs when used with Curl are shown below:
$ curl localhost:3000/hello
<h1>Hello, World!</h1>
$ curl localhost:3000/hello.txt
Hello, World!
$ curl localhost:3000/hello.json
{“text”:”Hello, World!”}
You can also pass parameters in the URL when you make a request. The param function can be used to retrieve the parameters as indicated below:
— params.hs
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Data.Monoid
main :: IO ()
main = scotty 3000 $ do
get “/user” $ do
name <- param “name”
html $ mconcat [“<h1>Hello “, name, “</h1>”]
You can start the above server using the runghc command:
$ runghc params.hs
Setting phasers to stun… (port 3000) (ctrl-c to quit)
You can now try the URL requests with and without parameters. The observed outputs are shown below:
$ curl localhost:3000/user
<h1>500 Internal Server Error</h1>Param: name not found!
$ curl localhost:3000/user?name=Shakthi
<h1>Hello Shakthi</h1>
The Hspec testing framework can be used for integration testing of the Web application. Install the
required dependencies as shown below:
$ cabal install happy hspec hspec-wai hspec-wai-json
The content type example has been updated to use Hspec, as illustrated below:
— content-type-spec.hs
{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}
module Main (main) where
import Data.Monoid
import Data.Text
import Network.Wai (Application)
import qualified Web.Scotty as W
import Data.Aeson (object, (.=))
import Test.Hspec
import Test.Hspec.Wai
import Test.Hspec.Wai.JSON
main :: IO ()
main = hspec spec
app :: IO Application
app = W.scottyApp $ do
W.get “/hello.txt” $ do
W.text “Hello, World!”
W.get “/hello” $ do
W.html $ mconcat [“<h1>”, “Hello, World!”, “</h1>”]
W.get “/hello.json” $ do
W.json $ object [“text” .= (“Hello, World!” :: Text)]
spec :: Spec
spec = with app $ do
describe “GET /” $ do
it “responds with text” $ do
get “/hello.txt” `shouldRespondWith` “Hello, World!”
it “responds with HTML” $ do
get “/hello” `shouldRespondWith` “<h1>Hello, World!</h1>”
it “responds with JSON” $ do
get “/hello.json” `shouldRespondWith` [json|{text:
“Hello, World!”}|]
You can compile the above code as follows:
$ ghc –make content-type-spec.hs
Linking content-type-spec …
The following output is observed when you run the above built test executable:
$ ./content-type-spec
GET /
responds with text
responds with HTML
responds with JSON
Finished in 0.0010 seconds
3 examples, 0 failures
Please refer to the hspec-wai Web page at https://github.com/hspec/hspec-wai for more information. Template support is available through many Haskell packages. The use of the blaze-html package is demonstrated below. Install the package first using the following command:
$ cabal install blaze-html
Consider a simple Web page with a header and three unordered lists. Using blaze-html, the template can be written in Haskell DSL as follows:
— template.hs
{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty as W
import Text.Blaze.Html5
import Text.Blaze.Html.Renderer.Text
main :: IO ()
main = scotty 3000 $ do
get “/” $ do
W.html . renderHtml $ do
h1 “Haskell list”
ul $ do
li “http://haskell.org”
li “http://learnyouahaskell.com/”
li “http://book.realworldhaskell.org/”
You can compile the above code using GHC:
$ ghc –make template.hs
Linking template …
You can then execute the built executable, which starts the server as shown below:
$ ./template
Setting phasers to stun… (port 3000) (ctrl-c to quit)
Opening a browser with URL localhost:3000 will render the expected HTML file. You can also verify the resultant HTML output using the Curl command as shown below:
$ curl localhost:3000
<h1>Haskell list</h1><ul><li>http://haskell.org</
li><li>http://learnyouahaskell.com/</li><li>http://book.
realworldhaskell.org/</li></ul>
It is good to separate the views from the actual application code. You can move the template content to a separate file as shown below:
— Haskell.hs
{-# LANGUAGE OverloadedStrings #-}
module Haskell where
import Text.Blaze.Html5
render :: Html
render = do
html $ do
body $ do
h1 “Haskell list”
ul $ do
li “http://haskell.org”
li “http://learnyouahaskell.com/”
li “http://book.realworldhaskell.org/”
The main application code is now simplified as shown below:
— template-file.hs
{-# LANGUAGE OverloadedStrings #-}
import qualified Haskell
import Web.Scotty as W
import Text.Blaze.Html
import Text.Blaze.Html.Renderer.Text
blaze :: Text.Blaze.Html.Html -> ActionM ()
blaze = W.html . renderHtml
main :: IO ()
main = scotty 3000 $ do
get “/” $ do
blaze Haskell.render
You need to place both the source files (Haskell.hs and template-file.hs) in the same top level directory, and you can then compile the template-file.hs file that will also compile the dependency Haskell.hs source file as shown below:
$ ghc –make template-file.hs
You can now run the server as follows:
$ ./template-file
Executing template-file produces the same output as in the case of the template.hs example.
$ curl localhost:3000
<html><body><h1>Haskell list</h1><ul><li>http://haskell.org</
li><li>http://learnyouahaskell.com/</li><li>http://book.
realworldhaskell.org/</li></ul></body></html>
You can refer to the Scotty wiki page at https://github.com/scotty-web/scotty/wiki for more information.
The clay package is a CSS preprocessor similar to LESS and Sass. You can install it using the following Cabal command:
$ cabal install clay
Let us consider a simple CSS example to generate a list of fonts to be used in the body section of an HTML page. The corresponding Clay Haskell embedded DSL looks like what’s shown below:
— clay-simple.hs
{-# LANGUAGE OverloadedStrings #-}
import Clay
main :: IO ()
main = putCss exampleStylesheet
exampleStylesheet :: Css
exampleStylesheet = body ? fontFamily [“Baskerville”,
“Georgia”, “Garamond”, “Times”] [serif]
You can compile the above code as follows:
$ ghc –make clay-simple.hs
[1 of 1] Compiling Main ( clay-simple.hs, clay-simple.o )
Linking clay-simple …
You can then execute clay-simple to generate the required
CSS output as shown below:
$ ./clay-simple
body
{
font-family : “Baskerville”,”Georgia”,”Garamond”,”Times”,
serif;
}
/* Generated with Clay, http://fvisser.nl/clay */
A more comprehensive example is shown below for the
HTML pre-tag:
— clay-pre.hs
{-# LANGUAGE OverloadedStrings #-}
import Clay
main :: IO ()
main = putCss $
pre ?
do border dotted (pt 1) black
whiteSpace (other “pre”)
fontSize (other “8pt”)
overflow (other “auto”)
padding (em 20) (em 0) (em 20) (em 0)
You can compile the above clay-pre.hs file as shown below:
$ ghc –make clay-pre.hs
Executing the above compiled clay-pre binary produces the following output:
$ ./clay-pre
pre
{
border : dotted 1pt rgb(0,0,0);
white-space : pre;
font-size : 8pt;
overflow : auto;
padding : 20em 0em 20em 0em;
}
/* Generated with Clay, http://fvisser.nl/clay */
You can also add custom values using the Other type class or the fallback operator ‘-:’ to explicitly specify values. For example:
— clay-custom.hs
{-# LANGUAGE OverloadedStrings #-}
import Clay
main :: IO ()
main = putCss $
body ?
do fontSize (other “11pt !important”)
“border” -: “0”
Compiling and executing the above code produces the
following output:
$ ghc –make clay-custom.hs
[1 of 1] Compiling Main ( clay-custom.hs, claycustom.
o )
Linking clay-custom …
$ ./clay-custom
body
{
font-size : 11pt !important;
border : 0;
}
/* Generated with Clay, http://fvisser.nl/clay */
You can explore more of Clay from the official project home page http://fvisser.nl/clay/.
A number of good books are available for further learning. The https://www.haskell.org website has plenty of useful resources. You can also join the haskell-cafe@haskell.org and beginners@haskell.org mailing lists (https://wiki.haskell.org/Mailing_lists ) for discussions. The folks in the #haskell channel on irc.freenode.net are also very helpful.
This article was written by Shakthi Kannan for OpenSourceForYou. Please buy OpenSourceForYou.
Note: Posted Under Creative Commons Attribution-NonCommercial 3.0
The post How to use Haskell for Web programming appeared first on All Latest News.