Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@SuuCH

HaskellでWebアプリケーションを作る

HaskellでWebアプリケーションを作る

研究でHaskellを用いてWebアプリケーションを作成している。
自分用のメモ、今後HaskellでWebアプリケーションを作る方のために記事を残したいと思う。
stackを用いる。
随時更新していく予定。

試したこと

・wai、warp
・yesod(勉強中)
・Lucid、Clay

参考にしたサイト

Haskellで超簡単にWebアプリケーションを作る(モナドも出てこないよ)
Haskell(wai) による Webアプリケーション開発の実際
Haskellでチャットサーバーを建ててみた
Haskellのフロントエンド開発をEDSLでモダンにする

WaiとWarp

waiとwarpを用いた方法は簡単にWebアプリケーションを作ることができる。
例として以下のコードを示す。

{-# LANGUAGE OverloadedStrings #-}
module Main where

import qualified Network.Wai.Handler.Warp as Warp
import qualified Network.Wai as Wai
import qualified Network.HTTP.Types as Htypes

main :: IO ()
main = do
  putStrLn "http://localhost:3000/"
  Warp.run 3000 hello


hello :: Wai.Application
hello req send = send $ Wai.responseBuilder Htypes.status200 [] "hello wai"

これをbuildする。localhost:3000を開けばhelloと表示されているわけである。
これでは、HTMLファイルが使えないので使えるようにする。

hello :: Wai.Application
hello req send = send $ Wai.responseFile Htypes.status200 [("Content-Type","text/html")] "index.html" Nothing

こうすればhtmlファイルが読み込まれる。ただし、CSSファイルが読み込まれない。
どうにかしてこれを可能にする。

hello = Static.staticApp $ settings { Static.ssIndices = indices}
  where
    settings = Static.embeddedSettings $(embedDir "static")
    indices = fromJust $ toPieces ["index.html"] 

こうすることでstaticフォルダ内のCSSを反映される。

Lucid、Clay

LucidはHTMLの言語内DSLでClayはCSSの言語内DSLである。
これを用いることで、htmlファイルやCSSファイルを記述しなくとも良い。
JavaScriptの言語内DSLにはSunroofというものがあるらしいが今回は使っていない。
書き方については、Hoogleで調べれたくさん出てくるので割愛する。

下記はCSSファイルが反映されず悩んでいたときに参考の記事を見て試してみたサンプルのコードである。
下記の方法では外部のCSSファイルが反映されなかった(たぶん)ため今回はWaiとWarpのみを用いた方法を用いる予定である。

main.hs
module Main where

import Network.Wai.Handler.Warp (run)
import Lib                      (app)

main :: IO ()
main = do
  putStrLn "http://localhost:3000/"
  run 3000 app
Lib.hs
module Lib where

import qualified Network.HTTP.Types as HTypes
import           Network.Wai (Application, responseLBS)
import           Html (lucidHtml)
import           Lucid (renderBST)

app :: Application
app _ respond = do
    bs <- renderBST lucidHtml
    respond $ responseLBS HTypes.status200 [] bs
Html.hs
{-# LANGUAGE OverloadedStrings #-}

module Html where

import Control.Monad.IO.Class ( MonadIO, liftIO)
import Lucid
import Clay                   (render)
import Css                    (clayCss)

lucidHtml :: MonadIO m => HtmlT m ()
lucidHtml = do
    doctype_
    html_ $ do
        head_ $ do
            meta_ [charset_ "UTF-8"]
            style_ [type_ "text/css"] $ render clayCss
            title_ "タイトル"
        body_ $ do
            div_ [id_ "pagebody"] $ do
            -- ヘッダー
                div_ [id_ "header"] $ do
                    p_ "タイトル"
                ul_ [id_ "menu"] $ do
                    li_ $ do
                        a_ [href_ "#"] "TOP"
                    li_ $ do
                        a_ [href_ "#"] "student"
                    li_ $ do
                        a_ [href_ "#"] "teacher"
                    li_ $ do
                        a_ [href_ "#"] "Developer"
        div_ [class_ "content"] $ do
            p_ "コンテンツ"
Css.hs
{-# LANGUAGE OverloadedStrings #-}
module Css where

import Clay
import Data.List.NonEmpty

halfPercent :: Size Percentage
halfPercent = 50

zero :: Size LengthUnit
zero = 0

clayCss :: Css
clayCss = do
    body ? do
        display flex
        minHeight (vh 100)
        flexDirection column
    byId "header" & do
        height (px 70)
        textAlign center
        backgroundColor cyan
        color darkgray
    byId "menu" & do
        listStyleType none
        display flex
        li ? do 
            width (px 140)
            textAlign center
            backgroundColor (rgb 51 51 51)
            height (px 50)
            lineHeight (px 50)
            marginRight (px 2)
            a ? do
                textDecoration none
                color (rgb 255 255 255)
                fontWeight bold
                padding (px 20) (px 20) (px 20) (px 20)
    byClass "content" & do
        backgroundColor darkorange
        textAlign center
        marginTop (px 10)
0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
SuuCH

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?