如何用标准化的,通用的纯函数编程语言Haskell来构建Web?Haskell构建的Web拥有着什么样的优点呢?让我们来看看构建的过程吧。

作者 | William Yao

译者 |弯月,责编 | maozz

出品 | CSDN(ID:CSDNnews)

以下为译文:

Haskell有大量的库可用于满足基本的后台需求,从日志输出到数据库访问,再到Web服务器的定义和路由,应有尽有。

拥有选择的自由固然很好,但如果你刚刚接触这个领域,那么大量的选择可能会让你目不暇接。也许你没法自信地判断出这些选择之间的区别。例如,你需要查询数据库。

那么,你需要Squeal提供的列名强保证,以及深度SQL嵌入功能吗?还是青睐Opaleye在保证类型安全的前提下的简单性?或者只是使用简单的postgresql-simple就好?还是使用Selda?或者……

我用最简单的库写了一个Web应用程序,一方面是想告诉你,你不需要担心技术栈是否足够先进,另一方面也是我自己的学习过程。

如果你不知道怎样用Haskell构建真正的应用程序,为什么不去学习呢?我会尽可能保持代码的简单性。

点击此处可查看源代码(https://gitlab.com/williamyaoh/haskell-web-stack)。

下面我们来看一看我选择的这些库,以及它们的功能,还有这个应用程序的功能。

这个Web应用程序究竟是什么呢?

它是一个网站,用户可以在这个网站上创建定时器和做笔记。

我举个例子说明该网站的用途:某人想设置多个定时器来跟踪多个反应物的过程,同时用笔记来记录他们需要关心的事情、下次制作配方时需要改进的事情,等等。

再举一个例子,某个人在玩MOBA游戏,比如英雄联盟或者刀塔2,他们可以在另一台显示器上打开一个页面来跟踪关键技能的冷却时间,同时用笔记记录宏操作、对手的组合,以及团战时需要关注技的冷却等。

在这个应用程序中我将演示:

  • 会话,用户可以刷新页面,或者关闭页面后再打开,但在打开之后应该看到相同的内容。

  • 持久化和数据库访问,我们需要将每个用户的定时器和笔记保存下来。另一个需求是定时器需要维持剩余的时间(用户设置了一个30分钟的定时器,然后不小心关闭了页面,应该如何?)

  • 运行时的配置,因为我们不能把数据库连接的信息硬编码到代码里。

  • 日志。日志对于Web应用的作用不言而喻。

我用到了哪些库?

路由和Web服务器:Spock

最终我选择了Spock,因为它易于使用。如果你用过Ruby的Sinatra,那么Spock应该不会陌生。Spock也自带了会话管理,这一点非常好。

例如,定义一个拥有几条路由的服务器,返回HTML和JSON,代码大致如下:

{-# LANGUAGE OverloadedStrings #-}import Web.Spock as Spock
import Web.Spock.Config as Spock
import Data.Aeson as Amain :: IO ()
main = dospockCfg <- defaultSpockCfg () PCNoDatabase ()runSpock 3000 $ spock spockCfg $ doget root $ doSpock.html "<div>Hello world!</div>"get "users" $ doSpock.json (A.object [ "users" .= users ])get ("users" <//> var <//> "friends") $ \userID -> doSpock.json (A.object [ "userID" .= (userID :: Int), "friends" .= A.Null ])where users :: [String]users = ["bob", "alice"]
数据库访问:postgresql-simple
postgresql-simple基本上只允许您对数据库运行原始SQL查询,而没有多余的装饰,例如防止注入攻击。它可以实现您的期望,仅此而已。{-# LANGUAGE OverloadedStrings #-}import Database.PostgreSQL.SimpleuserLoginsQuery :: Query
userLoginsQuery ="SELECT l.user_id, COUNT(1) FROM logins l GROUP BY l.user_id;"getUserLogins :: Connection -> IO [(Int, Int)]
getUserLogins conn = query_ conn userLoginsQuery

数据库访问:postgresql-simple

postgresql-simple可以让你在数据库上运行原始的SQL查询,它只提供最基本的额外处理,比如防止注入攻击等。它仅完成你需要的东西,没有任何额外的功能。

{-# LANGUAGE OverloadedStrings #-}import Database.PostgreSQL.SimpleuserLoginsQuery :: Query
userLoginsQuery ="SELECT l.user_id, COUNT(1) FROM logins l GROUP BY l.user_id;"getUserLogins :: Connection -> IO [(Int, Int)]
getUserLogins conn = query_ conn userLoginsQuery

配置:configurator

configurator能够从文件中读取配置,并解析成Haskell数据类型。与普通的配置文件读取器相比它的功能要多一些。

如果你习惯了直接读取配置文件,那么configurator还有一些额外功能。例如,配置项可以嵌套分组,configurator还提供了热重载来监视配置文件变化。

# An example config file.app_name = "The Whispering Fog"db {pool {stripes = 4resource_ttl = 300}username = "pallas"password = "thefalloflatinium"dbname = "italy"
}
{-# LANGUAGE OverloadedStrings #-}import Data.Configurator as Cfg
import Database.PostgreSQL.Simpledata MyAppConfig = MyAppConfig{ appName :: String, appDBConnection :: Connection}getAppConfig :: IO MyAppConfig
getAppConfig = docfgFile <- Cfg.load ["app-configuration.cfg"]name <- Cfg.require cfgFile "app_name"conn <- dousername <- 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}pure $ MyAppConfig{ appName = name, appDBConnection = conn}

日志:fast-logger

fast-logger提供了一个相对简单易用的日志解决方案。在Web应用程序的示例中,我只输出到了stderr,但它还可以支持输出日志到文件。虽然它支持许多类型,但绝大多数情况下,你需要定义一个辅助函数,接收一个LoggerSet,以及需要记录的信息。

import System.Log.FastLogger as LoglogMsg :: Log.LoggerSet -> String -> IO ()
logMsg logSet msg =Log.pushLogStrLn logSet (Log.toLogStr msg)doSomething :: IO ()
doSomething = dologSet <- Log.newStderrLoggerSet Log.defaultBufSizelogMsg logSet "message 1"logMsg logSet "message 2"

HTML生成:blaze-html

尽管本项目的后台并不需要生成太多HTML,但值得一提的是,blaze-html正是我需要的。

基本上它就是将HTML浅层嵌入到了Haskell DSL中。如果你会编写HTML,那你就会使用这个库。

{-# LANGUAGE OverloadedStrings #-}import Data.ByteString.Lazyimport Text.Blaze.Html5 as HTML
import Text.Blaze.Html5.Attributes as HTML hiding ( title )
import Text.Blaze.Html.Renderer.Utf8 as HTMLdashboardHTML :: HTML.Html
dashboardHTML = HTML.html $HTML.docTypeHtml $ doHTML.head $ doHTML.title "Timers and Notes"HTML.meta ! HTML.charset "utf-8"HTML.script ! HTML.src "/js/bundle.js" $ ""HTML.body $ doHTML.div ! HTML.id "content" $ ""dashboardBytes :: ByteString
dashboardBytes = HTML.renderHtml dashboardHTML

构建前端:make + npm

没错,它们并不是库。但我们依然需要某种JavaScript前端,因为定时器需要实时更新。Webpack能够生成JS包,而Make能够组装最终的应用程序。

这些东西无需我多说,网上有很多相关的资源。

我必须要用这些库吗?

当然不是。如果你第一次接触Haskell,那么有这些疑问是很自然的。不要让这篇文章限制了你的思路。尽管这个应用程序可以运行,但许多部分用于生产环境下的Haskell时并不理想。

例如,许多Haskell程序员很可能会使用Servant而不是Spock来定义API端点。如果你想了解其他库,那当然应该跟随你的直觉。

你可以把这些库和这个应用程序作为起点。我建议你用这些代码作为学习的机会,理解它的原理,然后自己试着修改。Haskell很好的一点就是它非常易于重构或者升级,而不会破坏已有的功能。

一旦掌握了这个应用程序,就可以用更高级的库来替换它们,来获得更多的保证。同时,这也是一个增量学习的过程。

将数据库访问的库从postgresql-simple升级到支持类型安全的库。我推荐Opaleye!

将API定义的库从Spock升级到Servant

利用QuickCheck或hedgehog增加自动测试。例如,你可以测试服务器的每个错误响应都返回了JSON格式的错误信息。

你还可以尝试替换前端和构建系统。

升级前端,使用PureScript或Elm来替换原始的JavaScript

升级构建系统,利用Shake替换make构建更健壮的系统

原文:https://williamyaoh.com/posts/2019-11-16-a-dead-simple-web-stack.html

本文为 CSDN 翻译,转载请注明来源出处。

【End】

Python学习线路高凊图,值得一看!

https://edu.csdn.net/topic/python115?utm_source=csdn_bw

热 文 推 荐 

☞拒绝成为比尔·盖茨的“万维网之父”,又要干大事!

☞神器推荐!在浏览器中运行 VS Code,随时随地写代码

☞多种方式创建 Entity Framework Core 上下文

☞网易发“暴力裁员”内部说明:给 N+1 赔偿后遭 61 万索赔,孙宇晨承包该离职员工看病钱!

☞倪光南:中国 5G 有望成为世界第一

☞微信几亿人在线的点赞、取消点赞系统,用Redis如何实现?

☞量子算命,在线掷筊:一个IBM量子云计算机的应用实践,代码都有了

☞从黑客文化看区块链开源社区的自我组织与成功之道

 点击阅读原文,参加中国开发者现状调查!

你点的每个“在看”,我都认真当成了喜欢

快速用 Haskell 构建超级简单的 Web 技术栈!相关推荐

  1. Nest的基本概念,以及如何使用Nest CLI来构建一个简单的Web应用程序

    Nest是一个用于构建高效.可扩展的Node.js服务器端应用程序的框架.它是基于Express.js构建的,并且提供了多种新特性和抽象层,可以让开发者更加轻松地构建复杂的应用程序. 本文将介绍Nes ...

  2. 用WEB技术栈开发NATIVE应用(二):WEEX 前端SDK原理详解

    摘要: WEEX依旧采取传统的web开发技术栈进行开发,同时app在终端的运行体验不输native app.其同时解决了开发效率.发版速度以及用户体验三个核心问题.那么WEEX是如何实现的?目前WEE ...

  3. 用WEB技术栈开发NATIVE应用:WEEX SDK原理详解

    摘要: WEEX依旧采取传统的web开发技术栈进行开发,同时app在终端的运行体验不输native app.其同时解决了开发效率.发版速度以及用户体验三个核心问题.那么WEEX是如何实现的?目前WEE ...

  4. Web技术栈中不可或缺的Linux技术

    随着第三次信息浪潮的冲击,web技术在近年来可谓发生了天翻地覆的变革.从单向信息的web1.0时代,逐步过渡到信息和人交互的web2.0再到数据主动与人发生关系的web3.0时代,这些成就无疑归功于W ...

  5. 【转】Node.js最新Web技术栈(2015年5月)

    nodejs是比较简单的,只有你有前端js基础,那就按照我的办法来吧!一周足矣 推荐技术栈 express 4.x (express最新版本,初学者先别去碰koa) mongoose(mongodb) ...

  6. Java Web 技术栈

    2019独角兽企业重金招聘Python工程师标准>>> Java Web 开发技术栈示意图: 转载于:https://my.oschina.net/u/2478308/blog/15 ...

  7. 如何用socket构建一个简单的Web Server

    2019独角兽企业重金招聘Python工程师标准>>> 背景 现代社会网络应用随处可见,不管我们是在浏览网页.发送电子邮件还是在线游戏都离不开网络应用程序,网络编程正在变得越来越重要 ...

  8. java jsf_使用Java和JSF构建一个简单的CRUD应用

    java jsf 使用Okta的身份管理平台轻松部署您的应用程序 使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护. 今天尝试Okta. JavaServer Fac ...

  9. 使用Java和JSF构建一个简单的CRUD应用

    使用Okta的身份管理平台轻松部署您的应用程序 使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护. 今天尝试Okta. JavaServer Faces(JSF)是用 ...

最新文章

  1. ASP.NET技巧:两个截取字符串的实用方法
  2. OSError: Unable to download 'ffmpeg.win32.exe'. Perhaps there is a no internet connection? If there
  3. wxpython dataview处理大量数据_38个常用Python库:数值计算、可视化、机器学习等8大领域都有了...
  4. 烧水壶起水沟了怎么办?
  5. 快速上手SpyGlass——CDC检查
  6. Vmware Workstation 6.5试用之二—支持设备的热插拔功能
  7. uniapp 自动播放背景音乐
  8. 悟透delphi 第十一章 面向对象数据库基础
  9. 解决Julia使用PyPlot库出现ERROR: ArgumentError: hasproperty of NULL PyObject问题
  10. 二分查找时间复杂度分析
  11. 关于instr和like的比较
  12. 协同级CRM能帮助企业带来哪些管理提升?
  13. vue开发必备神器:vue-devtools
  14. 10个超高清图片素材网站,不需要翻墙就可以直接访问
  15. 程序员面试总结 (非原创)
  16. selenium获取html源代码
  17. Docer容器的介绍(一)-------Docker基本概念和框架
  18. 西安信息资源网(计算机电子书)
  19. iOS APP 启动页面的使用
  20. 27计算机表演赛命题,(历史2)27届计算机表演赛命题搜索赛答案

热门文章

  1. 使用ajax的时候必须要加的几行代码
  2. [论文阅读] BCNet: Bidirectional collaboration network for edge-guided salient object detection
  3. [贪心|字符串] leetcode 3 无重复字符的最长子串
  4. android 高仿京东首页,android 粗略的 仿京东首页 嵌套方式滚动
  5. 华为商城抢购工具_华为套路太多,MATE40RS开启摇号模式,抽中资格仍需抢购
  6. yolov5安装pip install requirements.txt,pycocotools安装报错
  7. 剑指offer之青蛙跳台阶
  8. 2021-2025年中国电动门锁行业市场供需与战略研究报告
  9. android 360状态栏显示,Android高仿UC浏览器和360手机卫士消息常驻栏(通知栏)
  10. IT-游戏 学习资源思维导图(持续更新,欢迎关注点赞加评论)