快速用 Haskell 构建超级简单的 Web 技术栈( 二 )


getUserLogins conn = query_ conn userLoginsQuery
配置:configurator
configurator能够从文件中读取配置,并解析成Haskell数据类型 。与普通的配置文件读取器相比它的功能要多一些 。
如果你习惯了直接读取配置文件,那么configurator还有一些额外功能 。例如,配置项可以嵌套分组,configurator还提供了热重载来监视配置文件变化 。
 # An example config file.
App_name = "The Whispering Fog"
db {
pool {
stripes = 4
resource_ttl = 300
}
username = "pallas"
password = "thefalloflatinium"
dbname = "italy"
}
 {-# LANGUAGE OverloadedStrings #-}
import Data.Configurator as Cfg
import Database.PostgreSQL.Simple
data MyAppConfig = MyAppConfig
{ appName :: String
, appDBConnection :: Connection
}
getAppConfig :: IO MyAppConfig
getAppConfig = do
cfgFile <- Cfg.load ["app-configuration.cfg"]
name <- Cfg.require cfgFile "app_name"
conn <- do
username <- Cfg.require cfgFile "db.username"
password <- Cfg.require cfgFile "db.password"
dbname <- Cfg.require cfgFile "db.dbname"
connect $ defaultConnectInfo
{ connectUser = username
, connectPassword = password
, connectDatabase = dbname
【快速用 Haskell 构建超级简单的 Web 技术栈】}
pure $ MyAppConfig
{ appName = name
, appDBConnection = conn
}
日志:fast-logger
fast-logger提供了一个相对简单易用的日志解决方案 。在Web应用程序的示例中,我只输出到了stderr,但它还可以支持输出日志到文件 。虽然它支持许多类型,但绝大多数情况下,你需要定义一个辅助函数,接收一个LoggerSet,以及需要记录的信息 。
 import System.Log.FastLogger as Log
logMsg :: Log.LoggerSet -> String -> IO
logMsg logSet msg =
Log.pushLogStrLn logSet (Log.toLogStr msg)
doSomething :: IO
doSomething = do
logSet <- Log.newStderrLoggerSet Log.defaultBufSize
logMsg logSet "message 1"
logMsg logSet "message 2"
HTML生成:blaze-html
尽管本项目的后台并不需要生成太多HTML,但值得一提的是,blaze-html正是我需要的 。
基本上它就是将HTML浅层嵌入到了Haskell DSL中 。如果你会编写HTML,那你就会使用这个库 。
 {-# LANGUAGE OverloadedStrings #-}
import Data.ByteString.Lazy
import Text.Blaze.Html5 as HTML
import Text.Blaze.Html5.Attributes as HTML hiding ( title )
import Text.Blaze.Html.Renderer.Utf8 as HTML
dashboardHTML :: HTML.Html
dashboardHTML = HTML.html $
HTML.docTypeHtml $ do
HTML.head $ do
HTML.title "Timers and Notes"
HTML.meta ! HTML.charset "utf-8"
HTML.script ! HTML.src "/js/bundle.js" $ ""
HTML.body $ do
HTML.div ! HTML.id "content" $ ""
dashboardBytes :: ByteString
dashboardBytes = HTML.renderHtml dashboardHTML
构建前端:make + npm
没错,它们并不是库 。但我们依然需要某种JAVAScript前端,因为定时器需要实时更新 。Webpack能够生成JS包,而Make能够组装最终的应用程序 。
这些东西无需我多说,网上有很多相关的资源 。
3.我必须要用这些库吗?
当然不是 。如果你第一次接触Haskell,那么有这些疑问是很自然的 。不要让这篇文章限制了你的思路 。尽管这个应用程序可以运行,但许多部分用于生产环境下的Haskell时并不理想 。
例如,许多Haskell程序员很可能会使用Servant而不是Spock来定义API端点 。如果你想了解其他库,那当然应该跟随你的直觉 。
你可以把这些库和这个应用程序作为起点 。我建议你用这些代码作为学习的机会,理解它的原理,然后自己试着修改 。Haskell很好的一点就是它非常易于重构或者升级,而不会破坏已有的功能 。
一旦掌握了这个应用程序,就可以用更高级的库来替换它们,来获得更多的保证 。同时,这也是一个增量学习的过程 。
将数据库访问的库从postgresql-simple升级到支持类型安全的库 。我推荐Opaleye!
将API定义的库从Spock升级到Servant
利用QuickCheck或hedgehog增加自动测试 。例如,你可以测试服务器的每个错误响应都返回了JSON格式的错误信息 。
你还可以尝试替换前端和构建系统 。
升级前端,使用PureScript或Elm来替换原始的JavaScript
升级构建系统,利用Shake替换make构建更健壮的系统


推荐阅读